feat: 完善 API Token 管理功能

This commit is contained in:
2026-05-25 12:23:49 +08:00
parent 190ffa34f9
commit 4971cc380f
8 changed files with 279 additions and 44 deletions
+21 -7
View File
@@ -3,7 +3,7 @@ from typing import Any
from fastapi import APIRouter, Body, HTTPException, Request
from app.auth import resolve_login_context
from app.services.api_tokens import create_token, delete_token, list_tokens, regenerate_token, update_token
from app.services.api_tokens import create_token, delete_token, delete_tokens, list_tokens, regenerate_token, update_token
router = APIRouter(tags=["api-tokens"])
@@ -64,13 +64,16 @@ async def update_api_token(request: Request, payload: dict[str, Any] = Body(...)
if not token_id:
raise HTTPException(status_code=400, detail="缺少 Token ID")
changes: dict[str, Any] = {}
if "name" in payload:
changes["name"] = payload.get("name")
if "enabled" in payload:
changes["enabled"] = payload.get("enabled")
if "permanent" in payload or "expires_at" in payload:
changes["expires_at"] = _resolve_expires_at(payload)
try:
record = update_token(
token_id,
name=payload.get("name"),
enabled=payload.get("enabled"),
expires_at=_resolve_expires_at(payload),
)
record = update_token(token_id, **changes)
return {"success": True, "message": "API Token 已更新", "record": record}
except ValueError as exc:
raise _bad_expiration_error(exc) from exc
@@ -108,6 +111,17 @@ async def delete_api_token(request: Request, payload: dict[str, Any] = Body(...)
return {"success": True, "message": "API Token 已删除"}
@router.post("/api/tokens/batch-delete")
async def batch_delete_api_tokens(request: Request, payload: dict[str, Any] = Body(...)):
_require_login(request)
token_ids = payload.get("ids", [])
if not isinstance(token_ids, list) or not token_ids:
raise HTTPException(status_code=400, detail="请选择要删除的 Token")
deleted_count = delete_tokens([str(token_id) for token_id in token_ids])
return {"success": True, "message": f"已删除 {deleted_count} 个 API Token", "deleted_count": deleted_count}
@router.get("/api/docs-info")
async def docs_info(request: Request):
_require_login(request)
+6 -1
View File
@@ -8,6 +8,7 @@ from fastapi.responses import Response
from app import state
from app.config import HistoryRetentionConfig, RemoteDataConfig
from app.services.api_tokens import export_tokens, import_tokens
router = APIRouter(tags=["config"])
@@ -77,7 +78,9 @@ async def update_extract_fields(fields: list[dict[str, Any]] = Body(...)):
async def download_config():
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
filename = f"Configure_{timestamp}.json"
content = json.dumps(state.current_config().to_file_dict(), ensure_ascii=False, indent=2)
config_data = state.current_config().to_file_dict()
config_data["ApiTokens"] = export_tokens()
content = json.dumps(config_data, ensure_ascii=False, indent=2)
return Response(
content=content,
media_type="application/json",
@@ -97,6 +100,8 @@ async def upload_config(file: UploadFile = File(...)):
state.reload_config()
_apply_config_data(data)
if "ApiTokens" in data:
import_tokens(data["ApiTokens"])
state.config.save()
return {"success": True, "message": "配置文件上传成功", "update": state.config.update}
except json.JSONDecodeError as exc: