You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

FastAPI中能否将HTTPBearer.credentials转换为Pydantic BaseModel?

问题描述

我正在用FastAPI的HTTPBearer类从请求头接收授权令牌,当前依赖逻辑是把token.credentials(JSON字符串)手动解析成自定义的ClassroomAuthCredentials模型。我希望能像定义请求体结构那样,直接指定token.credentials的数据结构——既方便直接访问属性,也能在Swagger的授权模态框里展示格式说明,让团队开发者不用猜测必填字段。

当前依赖代码:

classroom_auth_scheme = HTTPBearer(
    scheme_name="Google Auth Credentials",
    bearerFormat="Bearer",
    description="O-Auth2 Credentials obtained on frontend, used to authenticate with Google services",
)


def get_classroom_token(
    token: str = Depends(classroom_auth_scheme),
) -> requests.ClassroomAuthCredentials:
    """Converts a json string of Authorization Bearer token into ClassroomAuthCredentials class

    Args:
        token (str, optional): Autorization Header Bearer Token. Defaults to Depends(auth_scheme).

    Raises:
        HTTPException: 400 level response meaning the token was not in the correct format

    Returns:
        requests.ClassroomAuthCredentials
    """
    try:
        # token.credentials is a JSON String -> want: pydantic Basemodel
        token_dict = json.loads(token.credentials)
        token = requests.ClassroomAuthCredentials.parse_obj(token_dict)
        return token
    except Exception as e:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=f"{e}",
        )

路由使用方式:

@router.post("/test-auth", summary="Validate authentication with Google Classroom API")
async def test_auth(token=Depends(get_classroom_token)):
    try:
        gc_service_test = get_service(token)
        gc_api_test = ClassroomApi(service=gc_service_test)
        user_profile = gc_api_test.get_user_profile("me")

        response: responses.ListGoogleClassroomCourses = {
            "message": f"Auth Credentials Are Valid",
            "userProfile": user_profile,
        }
        return JSONResponse(response)

    except errors.HttpError as error:
      # handle exceptions...

我已定义对应的BaseModel:

class ClassroomAuthCredentials(BaseModel):
    token: str = Field(..., example="MyJWT")
    clientId: str = Field(..., example="myClientId")
    clientSecret: str = Field(..., example="myClientSecret")
    refreshToken: str = Field(..., example="myRefreshToken")
    scopes: list[str] = Field(
        ...,
        example=[
            "https://www.googleapis.com/auth/classroom.courses.readonly",
            "https://www.googleapis.com/auth/classroom.coursework.students",
        ],
    )
解决方案

完全可以实现,核心是自定义继承HTTPBearer的认证方案类,让它直接处理JSON到Pydantic模型的解析,同时把模型结构同步到Swagger文档中。

步骤1:自定义认证方案类

替换原有HTTPBearer实例,改为继承它的子类,重写__call__方法完成自动解析:

from fastapi import HTTPException, status, Depends
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from pydantic import ValidationError
import json

class ClassroomAuthScheme(HTTPBearer):
    def __init__(self):
        super().__init__(
            scheme_name="Google Auth Credentials",
            bearerFormat="Bearer",
            description="O-Auth2 Credentials obtained on frontend, used to authenticate with Google services. Format: JSON string matching ClassroomAuthCredentials schema",
        )
    
    async def __call__(self, request):
        credentials: HTTPAuthorizationCredentials = await super().__call__(request)
        try:
            # 直接将凭证解析为Pydantic模型
            token_data = ClassroomAuthCredentials.parse_raw(credentials.credentials)
            return token_data
        except (json.JSONDecodeError, ValidationError) as e:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail=f"Invalid token format: {str(e)}"
            )

# 创建认证方案实例
classroom_auth_scheme = ClassroomAuthScheme()

# 简化依赖函数,直接返回模型实例
def get_classroom_token(
    token: ClassroomAuthCredentials = Depends(classroom_auth_scheme),
) -> ClassroomAuthCredentials:
    return token

步骤2:更新路由使用

路由无需大幅修改,token现在已是ClassroomAuthCredentials实例,可直接访问属性:

@router.post("/test-auth", summary="Validate authentication with Google Classroom API")
async def test_auth(token: ClassroomAuthCredentials = Depends(get_classroom_token)):
    try:
        # 直接使用token.token、token.clientId等属性
        gc_service_test = get_service(token)
        gc_api_test = ClassroomApi(service=gc_service_test)
        user_profile = gc_api_test.get_user_profile("me")

        response = {
            "message": "Auth Credentials Are Valid",
            "userProfile": user_profile,
        }
        return JSONResponse(response)

    except errors.HttpError as error:
        # 异常处理逻辑
        ...

步骤3:优化Swagger文档展示

在认证方案的description中添加Markdown格式的示例,让开发者在授权模态框里直接看到格式要求:

description="""O-Auth2 Credentials obtained on frontend, used to authenticate with Google services.  
**Required JSON Format**:
```json
{
  "token": "MyJWT",
  "clientId": "myClientId",
  "clientSecret": "myClientSecret",
  "refreshToken": "myRefreshToken",
  "scopes": [
    "https://www.googleapis.com/auth/classroom.courses.readonly",
    "https://www.googleapis.com/auth/classroom.coursework.students"
  ]
}
```""",

核心优势

  • 无需手动调用json.loads和parse_obj,Pydantic自动完成验证与解析
  • 直接通过模型属性访问数据,代码更简洁
  • Swagger文档自动展示格式要求,降低团队协作成本
  • 验证错误信息更精准,包含Pydantic的字段级提示

内容的提问来源于stack exchange,提问作者Rafael Zasas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 20:45:32