FastAPI GET请求中aud字段被识别为请求体的解决方法
解决FastAPI GET请求中BaseModel被当作请求体解析的问题
你的问题在于直接将AccessClaims(继承自BaseModel)作为Depends()的参数,FastAPI会默认把这种BaseModel类型的依赖当作请求体模型处理,而GET请求并不支持请求体,因此才会试图从请求体中解析aud等字段。
核心解决方案:自定义JWT解析依赖函数
正确的做法是编写一个专门的依赖函数,负责从请求中提取并解析JWT令牌,验证后返回AccessClaims实例,而非直接将模型类传入Depends。
示例代码如下:
from jose import JWTError, jwt from fastapi import Depends, HTTPException, status, APIRouter from fastapi.security import OAuth2PasswordBearer from pydantic import BaseModel, Optional, Union, List import time # 配置JWT参数(根据实际情况修改) SECRET_KEY = "your-actual-secret-key" ALGORITHM = "HS256" OAUTH2_SCHEME = OAuth2PasswordBearer(tokenUrl="token") router = APIRouter() class JWTClaims(BaseModel): iat: int exp: int aud: Optional[Union[str, List[str]]] iss: str sub: str azp: str class AccessClaims(JWTClaims): scope: str async def get_validated_claims(token: str = Depends(OAUTH2_SCHEME)) -> AccessClaims: # 定义凭证验证失败的异常 credentials_error = HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="无法验证凭证", headers={"WWW-Authenticate": "Bearer"}, ) try: # 解码JWT令牌,可根据需求添加audience验证等逻辑 payload = jwt.decode( token, SECRET_KEY, algorithms=[ALGORITHM], # 如果需要验证audience,取消下面注释并填写对应值 # audience="your-audience-value" ) # 将解码后的载荷转换为AccessClaims实例 claims = AccessClaims(**payload) # 可选:添加令牌过期检查 current_timestamp = int(time.time()) if claims.exp < current_timestamp: raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="令牌已过期") except JWTError: raise credentials_error return claims @router.get("/client") async def get_user_client(claims: AccessClaims = Depends(get_validated_claims)): # 这里可以正常使用claims中的字段 return {"client_info": f"用户ID: {claims.sub}, 权限范围: {claims.scope}"}
原理说明
- FastAPI对
Depends()的处理逻辑:当传入的是一个类(如AccessClaims),它会尝试调用该类的构造方法,默认从请求体中获取数据填充字段;而传入自定义函数时,会执行函数内的逻辑,返回的结果才会赋值给参数。 - 自定义依赖函数中,我们通过
OAuth2PasswordBearer从请求头的Authorization字段提取JWT令牌,解码后转换为AccessClaims模型,同时添加了异常处理确保凭证有效性。
内容的提问来源于stack exchange,提问作者equatorial_daydreamer
相关产品推荐
相关产品推荐

