"""访问门控 API 与管理接口。""" from __future__ import annotations from fastapi import APIRouter, Request from app import auth from app import uuid_store router = APIRouter(prefix="/api/auth", tags=["auth"]) admin_router = APIRouter(prefix="/api/admin", tags=["admin"]) @router.post("/verify") def verify_credential(req: auth.VerifyIn) -> auth.VerifyOut: """校验管理员令牌或普通 UUID,成功后返回访问令牌及角色。""" role = auth.verify_credential(req.credential) if role: token = auth.create_access_token(role) return auth.VerifyOut(valid=True, role=role.value, token=token) return auth.VerifyOut(valid=False, role=None, token=None) @router.get("/status") def auth_status(request: Request) -> auth.AuthStatusOut: """返回当前门控状态、当前请求是否通过校验及角色。""" enabled = auth.access_control_enabled() token = auth.get_access_token_from_request(request) role = auth.validate_access_token(token) return auth.AuthStatusOut( enabled=enabled, verified=role is not None, role=role.value if role else None, ) # ===== 管理员 UUID 管理 ===== @admin_router.get("/uuids") def list_uuids(request: Request) -> list[auth.UuidRecordOut]: """列出所有动态 UUID(仅管理员)。""" auth.require_admin(request) records = uuid_store.list_uuids() return [ auth.UuidRecordOut( uuid=r["uuid"], label=r.get("label", ""), enabled=r.get("enabled", True), created_at=r.get("created_at", 0), ) for r in records ] @admin_router.post("/uuids") def create_uuid(req: auth.UuidCreateIn, request: Request) -> auth.UuidRecordOut: """创建新的访问 UUID(仅管理员)。""" auth.require_admin(request) record = uuid_store.create(req.label) return auth.UuidRecordOut( uuid=record["uuid"], label=record["label"], enabled=record["enabled"], created_at=record["created_at"], ) @admin_router.delete("/uuids/{uuid}") def delete_uuid(uuid: str, request: Request) -> dict: """删除访问 UUID(仅管理员)。""" auth.require_admin(request) ok = uuid_store.delete(uuid) return {"ok": ok} @admin_router.put("/uuids/{uuid}/toggle") def toggle_uuid(uuid: str, request: Request, enabled: bool) -> dict: """启用/禁用访问 UUID(仅管理员)。""" auth.require_admin(request) ok = uuid_store.toggle(uuid, enabled) return {"ok": ok}