"""文档接口(/docs、/redoc、/openapi.json)的 HTTP Basic Auth 依赖。 凭据明文存放于 config.yaml 的 docs 段;该文件仅在本机以 root 持有,比较使用 secrets.compare_digest 以保证常量时间。 """ from __future__ import annotations import secrets from fastapi import Depends, HTTPException, status from fastapi.security import HTTPBasic, HTTPBasicCredentials from .config import get_settings _security = HTTPBasic(auto_error=False) def require_docs_auth( credentials: HTTPBasicCredentials | None = Depends(_security), ) -> str: cfg = get_settings().docs realm = f'Basic realm="{cfg.realm}"' if not cfg.enabled: raise HTTPException(status.HTTP_404_NOT_FOUND, "docs 已禁用") if not cfg.password: raise HTTPException( status.HTTP_503_SERVICE_UNAVAILABLE, "docs 鉴权未配置:请在 config.yaml 的 docs.password 填密码后重启", ) if credentials is None: raise HTTPException( status.HTTP_401_UNAUTHORIZED, "需要认证", headers={"WWW-Authenticate": realm}, ) user_ok = secrets.compare_digest(credentials.username, cfg.username) pw_ok = secrets.compare_digest(credentials.password, cfg.password) if not (user_ok and pw_ok): raise HTTPException( status.HTTP_401_UNAUTHORIZED, "用户名或密码错误", headers={"WWW-Authenticate": realm}, ) return credentials.username