refactor: 移除旧版单文件管理后台兼容
This commit is contained in:
@@ -234,8 +234,6 @@ def change_password(
|
||||
body: ChangePasswordRequest,
|
||||
principal: AdminPrincipal = Depends(require_permission("admin:access")),
|
||||
):
|
||||
if principal.auth_type == "legacy_token":
|
||||
raise HTTPException(status_code=400, detail="兼容令牌登录不能修改用户密码,请使用用户名密码登录")
|
||||
new_password = body.new_password.strip()
|
||||
if len(new_password) < 8:
|
||||
raise HTTPException(status_code=400, detail="新密码至少需要 8 个字符")
|
||||
|
||||
@@ -66,16 +66,16 @@ def normalize_install_root(value: str, fallback: str = "..") -> str:
|
||||
def admin_change_token(body: ChangeAdminTokenRequest, auth=Depends(require_permission("admin:manage"))):
|
||||
new_token = body.new_token.strip()
|
||||
if len(new_token) < 8:
|
||||
raise HTTPException(status_code=400, detail="新兼容令牌至少需要 8 个字符")
|
||||
raise HTTPException(status_code=400, detail="新服务端兜底令牌至少需要 8 个字符")
|
||||
if len(new_token) > 128:
|
||||
raise HTTPException(status_code=400, detail="新兼容令牌不能超过 128 个字符")
|
||||
raise HTTPException(status_code=400, detail="新服务端兜底令牌不能超过 128 个字符")
|
||||
try:
|
||||
persist_env_value(ENV_FILE_PATH, "ADMIN_TOKEN", new_token)
|
||||
except Exception as exc:
|
||||
raise HTTPException(status_code=500, detail=f"令牌已通过校验,但写入 .env 失败: {exc}")
|
||||
set_admin_token(new_token)
|
||||
os.environ["ADMIN_TOKEN"] = new_token
|
||||
return {"code": 0, "msg": f"兼容管理员令牌已更新,并已写入 {ENV_FILE_PATH}"}
|
||||
return {"code": 0, "msg": f"服务端兜底令牌已更新,并已写入 {ENV_FILE_PATH}"}
|
||||
|
||||
|
||||
@router.get("/admin/runtime-config")
|
||||
|
||||
@@ -7,7 +7,6 @@ from app.core.config import configured_path
|
||||
|
||||
router = APIRouter(include_in_schema=False)
|
||||
|
||||
ADMIN_HTML_PATH = configured_path("ADMIN_HTML_PATH", "legacy/admin.html")
|
||||
ADMIN_UI_DIST_PATH = configured_path("ADMIN_UI_DIST_PATH", "admin-ui/dist")
|
||||
ADMIN_UI_INDEX_PATH = ADMIN_UI_DIST_PATH / "index.html"
|
||||
ADMIN_UI_ASSETS_PATH = ADMIN_UI_DIST_PATH / "assets"
|
||||
@@ -23,20 +22,10 @@ def mount_admin_assets(app: FastAPI):
|
||||
|
||||
|
||||
@router.get("/")
|
||||
@router.get("/admin.html")
|
||||
def admin_page():
|
||||
if ADMIN_UI_INDEX_PATH.is_file():
|
||||
return FileResponse(ADMIN_UI_INDEX_PATH, headers={"Cache-Control": "no-store"})
|
||||
if not ADMIN_HTML_PATH.is_file():
|
||||
raise HTTPException(status_code=404, detail="管理页面文件不存在")
|
||||
return FileResponse(ADMIN_HTML_PATH, headers={"Cache-Control": "no-store"})
|
||||
|
||||
|
||||
@router.get("/legacy-admin.html")
|
||||
def legacy_admin_page():
|
||||
if not ADMIN_HTML_PATH.is_file():
|
||||
raise HTTPException(status_code=404, detail="旧管理页面文件不存在")
|
||||
return FileResponse(ADMIN_HTML_PATH, headers={"Cache-Control": "no-store"})
|
||||
if not ADMIN_UI_INDEX_PATH.is_file():
|
||||
raise HTTPException(status_code=404, detail="管理后台前端文件不存在,请先构建 admin-ui/dist")
|
||||
return FileResponse(ADMIN_UI_INDEX_PATH, headers={"Cache-Control": "no-store"})
|
||||
|
||||
|
||||
@router.get("/favicon.ico")
|
||||
|
||||
+1
-1
@@ -20,7 +20,7 @@ async def admin_audit_middleware(request: Request, call_next):
|
||||
if should_audit:
|
||||
try:
|
||||
principal = getattr(request.state, "admin_principal", None)
|
||||
token = request.headers.get("authorization", "") or request.headers.get("X-Admin-Token", "")
|
||||
token = request.headers.get("authorization", "")
|
||||
conn = db.get_conn()
|
||||
conn.execute(
|
||||
"""INSERT INTO admin_audit_logs
|
||||
|
||||
+1
-23
@@ -165,16 +165,6 @@ def principal_from_user_row(row, auth_type: str = "jwt") -> AdminPrincipal:
|
||||
)
|
||||
|
||||
|
||||
def legacy_admin_principal() -> AdminPrincipal:
|
||||
return AdminPrincipal(
|
||||
username="legacy-admin-token",
|
||||
display_name="兼容管理员令牌",
|
||||
roles=["super_admin"],
|
||||
permissions=role_permissions(["super_admin"]),
|
||||
auth_type="legacy_token",
|
||||
)
|
||||
|
||||
|
||||
def create_jwt_token(username: str, token_type: str, expires_delta: timedelta, roles: list[str] | None = None) -> tuple[str, str, datetime]:
|
||||
now = utc_now()
|
||||
expires_at = now + expires_delta
|
||||
@@ -271,21 +261,11 @@ def persist_env_value(path: Path, key: str, value: str) -> bool:
|
||||
return True
|
||||
|
||||
|
||||
def legacy_admin_auth(X_Admin_Token: str = Header("")):
|
||||
# Backward-compatible token-only auth for old scripts.
|
||||
token = X_Admin_Token if isinstance(X_Admin_Token, str) else ""
|
||||
if token and secrets.compare_digest(token, settings.admin_token):
|
||||
return legacy_admin_principal()
|
||||
raise HTTPException(status_code=403, detail="后台密钥错误,禁止访问")
|
||||
|
||||
|
||||
def current_admin(
|
||||
request: Request,
|
||||
Authorization: str = Header(""),
|
||||
X_Admin_Token: str = Header(""),
|
||||
) -> AdminPrincipal:
|
||||
authorization = Authorization if isinstance(Authorization, str) else ""
|
||||
admin_token = X_Admin_Token if isinstance(X_Admin_Token, str) else ""
|
||||
if authorization.lower().startswith("bearer "):
|
||||
payload = decode_jwt_token(authorization[7:].strip(), "access")
|
||||
username = str(payload.get("sub") or "")
|
||||
@@ -295,9 +275,7 @@ def current_admin(
|
||||
principal = principal_from_user_row(row)
|
||||
request.state.admin_principal = principal
|
||||
return principal
|
||||
principal = legacy_admin_auth(admin_token)
|
||||
request.state.admin_principal = principal
|
||||
return principal
|
||||
raise HTTPException(status_code=401, detail="请先登录管理后台")
|
||||
|
||||
|
||||
admin_auth = current_admin
|
||||
|
||||
@@ -106,7 +106,7 @@ def crash_report_test_values(api_base_url: str) -> dict:
|
||||
"说明": "如果为空,查询/下载接口会使用 ADMIN_TOKEN。",
|
||||
},
|
||||
"ADMIN_TOKEN": {
|
||||
"用途": "管理后台令牌;当 CRASH_ADMIN_TOKEN 为空时也用于查询/下载崩溃报告",
|
||||
"用途": "服务端兜底令牌;当 CRASH_ADMIN_TOKEN 为空时也用于查询/下载崩溃报告",
|
||||
"token": admin_token,
|
||||
},
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user