feat(api): add API key authentication to backend endpoints
Add API key security using fastapi.security.APIKeyHeader to protect /v1/completions and /v1/ocr endpoints. Updated frontend to include X-API-Key header in API requests. Also changed default API base URL from http://149.104.29.239:8001 to https://api.learnteach.tech:8002.
This commit is contained in:
+15
-3
@@ -1,4 +1,5 @@
|
|||||||
from fastapi import FastAPI, Request
|
from fastapi import FastAPI, Request, HTTPException, Security
|
||||||
|
from fastapi.security import APIKeyHeader
|
||||||
from fastapi.middleware.cors import CORSMiddleware
|
from fastapi.middleware.cors import CORSMiddleware
|
||||||
from fastapi.responses import StreamingResponse, JSONResponse
|
from fastapi.responses import StreamingResponse, JSONResponse
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
@@ -27,6 +28,17 @@ app.add_middleware(
|
|||||||
allow_headers=["*"],
|
allow_headers=["*"],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
API_KEY = "your-secret-key-here" # 建议从环境变量读取
|
||||||
|
api_key_header = APIKeyHeader(name="X-API-Key")
|
||||||
|
|
||||||
|
async def get_api_key(api_key: str = Security(api_key_header)):
|
||||||
|
if api_key != API_KEY:
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=403,
|
||||||
|
detail="Could not validate credentials"
|
||||||
|
)
|
||||||
|
return api_key
|
||||||
|
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
class UserPreferences(BaseModel):
|
class UserPreferences(BaseModel):
|
||||||
@@ -58,7 +70,7 @@ def get_client_ip(request: Request) -> str:
|
|||||||
return request.headers.get("X-Client-IP") or request.client.host if request.client else "unknown"
|
return request.headers.get("X-Client-IP") or request.client.host if request.client else "unknown"
|
||||||
|
|
||||||
@app.post("/v1/completions")
|
@app.post("/v1/completions")
|
||||||
async def create_completion(request: Request, req: CompletionRequest):
|
async def create_completion(request: Request, req: CompletionRequest, api_key: str = Security(get_api_key)):
|
||||||
request_id = str(uuid.uuid4())[:8]
|
request_id = str(uuid.uuid4())[:8]
|
||||||
|
|
||||||
client_ip = "hidden"
|
client_ip = "hidden"
|
||||||
@@ -122,7 +134,7 @@ async def create_completion(request: Request, req: CompletionRequest):
|
|||||||
return JSONResponse(content={"error": str(e)}, status_code=500)
|
return JSONResponse(content={"error": str(e)}, status_code=500)
|
||||||
|
|
||||||
@app.post("/v1/ocr")
|
@app.post("/v1/ocr")
|
||||||
async def ocr_image(request: OCRRequest):
|
async def ocr_image(request: OCRRequest, api_key: str = Security(get_api_key)):
|
||||||
request_id = str(uuid.uuid4())[:8]
|
request_id = str(uuid.uuid4())[:8]
|
||||||
try:
|
try:
|
||||||
logger.info(
|
logger.info(
|
||||||
|
|||||||
@@ -233,7 +233,10 @@ const performOCR = async (file, cacheKey, imageHash = '') => {
|
|||||||
try {
|
try {
|
||||||
const res = await fetch(OCR_URL, {
|
const res = await fetch(OCR_URL, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'X-API-Key': 'your-secret-key-here'
|
||||||
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
image: base64,
|
image: base64,
|
||||||
filename: file.name,
|
filename: file.name,
|
||||||
|
|||||||
+4
-1
@@ -22,7 +22,10 @@ export async function fetchSuggestion(prefix, suffix, signal, apiUrl = API_URL)
|
|||||||
try {
|
try {
|
||||||
const settings = useSettingsStore()
|
const settings = useSettingsStore()
|
||||||
const clientIP = await getClientIP()
|
const clientIP = await getClientIP()
|
||||||
const headers = { 'Content-Type': 'application/json' }
|
const headers = {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'X-API-Key': 'your-secret-key-here'
|
||||||
|
}
|
||||||
|
|
||||||
// Only send IP if privacy mode is OFF
|
// Only send IP if privacy mode is OFF
|
||||||
if (clientIP && !settings.privacyMode) {
|
if (clientIP && !settings.privacyMode) {
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
export const DEBUG = import.meta.env.DEV
|
export const DEBUG = import.meta.env.DEV
|
||||||
|
|
||||||
const API_BASE_URL = import.meta.env.VITE_API_BASE_URL || 'http://149.104.29.239:8001'
|
const API_BASE_URL = import.meta.env.VITE_API_BASE_URL || 'https://api.learnteach.tech:8002'
|
||||||
|
|
||||||
export const API_URL = import.meta.env.VITE_API_URL || `${API_BASE_URL}/v1/completions`
|
export const API_URL = import.meta.env.VITE_API_URL || `${API_BASE_URL}/v1/completions`
|
||||||
export const OCR_URL = import.meta.env.VITE_OCR_URL || `${API_BASE_URL}/v1/ocr`
|
export const OCR_URL = import.meta.env.VITE_OCR_URL || `${API_BASE_URL}/v1/ocr`
|
||||||
|
|||||||
Reference in New Issue
Block a user