| |
| """ |
| Web UI 认证相关的 FastAPI 依赖项。 |
| 定义了用于验证 JWT 令牌的依赖函数。 |
| """ |
| import logging |
| from typing import Optional, Dict, Any |
|
|
| from fastapi import Depends, HTTPException, status, Request |
| from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials |
|
|
| |
| from app.core.security.jwt import decode_access_token |
|
|
| logger = logging.getLogger('my_logger') |
|
|
| |
| |
| |
| |
| |
| bearer_scheme = HTTPBearer(auto_error=False) |
|
|
| async def verify_jwt_token( |
| request: Request, |
| credentials: Optional[HTTPAuthorizationCredentials] = Depends(bearer_scheme) |
| ) -> Dict[str, Any]: |
| """ |
| FastAPI 依赖项函数,用于验证通过 HTTP Bearer 方案提供的 JWT 令牌。 |
| 此函数会检查 Authorization 请求头,提取 Bearer Token,然后解码并验证它。 |
| |
| Args: |
| request (Request): FastAPI 请求对象 (当前未使用)。 |
| credentials (Optional[HTTPAuthorizationCredentials]): FastAPI 从 Authorization 头提取的凭证对象。 |
| 如果请求头不存在或格式不正确,此值为 None。 |
| |
| Returns: |
| Dict[str, Any]: 如果令牌有效,返回解码后的 JWT payload (包含用户信息,如 'sub' 和 'admin')。 |
| |
| Raises: |
| HTTPException: |
| - 401 Unauthorized: 如果没有提供有效的 Bearer Token,或者 Token 无效、过期、或缺少必要信息。 |
| """ |
| logger.debug("verify_jwt_token: 开始验证 JWT token (仅从 Bearer Header 获取)") |
|
|
| token = None |
| |
| if credentials and credentials.scheme.lower() == "bearer": |
| logger.debug("verify_jwt_token: 从 Authorization 头中找到 Bearer token。") |
| token = credentials.credentials |
|
|
| |
| if not token: |
| logger.warning("verify_jwt_token: 未找到有效的认证令牌 (仅检查 Bearer Header)。") |
| |
| raise HTTPException( |
| status_code=status.HTTP_401_UNAUTHORIZED, |
| detail="缺少有效的认证令牌", |
| headers={"WWW-Authenticate": "Bearer"}, |
| ) |
|
|
| |
| logger.debug(f"verify_jwt_token: 提取到 token (前10位): {token[:10]}...") |
|
|
| |
| |
| payload = decode_access_token(token) |
|
|
| |
| if payload is None: |
| logger.warning(f"verify_jwt_token: JWT token 无效或已过期 (Token: {token[:10]}...)") |
| |
| raise HTTPException( |
| status_code=status.HTTP_401_UNAUTHORIZED, |
| detail="无效或已过期的 token", |
| headers={"WWW-Authenticate": "Bearer"}, |
| ) |
|
|
| |
| logger.debug(f"verify_jwt_token: JWT payload 解码成功: {payload}") |
|
|
| |
| |
| user_key = payload.get("sub") |
| is_admin = payload.get("admin", False) |
| if not user_key: |
| logger.warning(f"JWT token 有效,但缺少 'sub' (用户标识符) 字段。Payload: {payload}") |
| |
| raise HTTPException( |
| status_code=status.HTTP_401_UNAUTHORIZED, |
| detail="无效的 token (缺少用户信息)", |
| headers={"WWW-Authenticate": "Bearer"}, |
| ) |
|
|
| |
| logger.debug(f"verify_jwt_token: JWT token 验证成功. User Key: {user_key[:8]}..., Is Admin: {is_admin}") |
| |
| return payload |
|
|
| async def verify_jwt_token_optional( |
| credentials: Optional[HTTPAuthorizationCredentials] = Depends(bearer_scheme) |
| ) -> Optional[Dict[str, Any]]: |
| """ |
| FastAPI 依赖项函数,可选地验证通过 HTTP Bearer 方案提供的 JWT 令牌。 |
| 如果令牌有效,返回解码后的 payload;如果无效、过期或未提供,则返回 None。 |
| |
| Args: |
| credentials (Optional[HTTPAuthorizationCredentials]): FastAPI 从 Authorization 头提取的凭证对象。 |
| |
| Returns: |
| Optional[Dict[str, Any]]: 如果令牌有效,返回解码后的 JWT payload,否则返回 None。 |
| """ |
| logger.debug("verify_jwt_token_optional: 开始可选的 JWT token 验证") |
| token = None |
| if credentials and credentials.scheme.lower() == "bearer": |
| token = credentials.credentials |
| logger.debug(f"verify_jwt_token_optional: 提取到 token (前10位): {token[:10]}...") |
|
|
| if not token: |
| logger.debug("verify_jwt_token_optional: 未找到 Bearer token。") |
| return None |
|
|
| payload = decode_access_token(token) |
|
|
| if payload is None: |
| logger.debug(f"verify_jwt_token_optional: JWT token 无效或已过期 (Token: {token[:10]}...)") |
| return None |
|
|
| user_key = payload.get("sub") |
| if not user_key: |
| logger.warning(f"verify_jwt_token_optional: JWT token 有效,但缺少 'sub' 字段。Payload: {payload}") |
| return None |
|
|
| logger.debug(f"verify_jwt_token_optional: JWT token 验证成功. User Key: {user_key[:8]}...") |
| return payload |
|
|