FastAPI JWT认证中token返回None的原因及解决办法
问题原因
TokenSchema字段不符合OAuth2规范
FastAPI的OAuth2PasswordBearer遵循OAuth2标准,默认要求返回的token字段为access_token,且需附带token_type(值为bearer)。你的TokenSchema定义为accesstoken(无下划线),且登录接口未返回token_type,会导致客户端无法正确识别token格式,或后续认证逻辑无法提取有效token。get_current_user中payload解析逻辑错误
你从JWT解码后的payload中直接取token_data = payload['sub'],但sub字段通常是用户标识(如邮箱)而非包含exp的对象,后续访问token_data.exp会触发异常。再加上auto_error=False的设置,依赖会返回None而非抛出异常,最终导致token变量为None。auto_error设置不当
auto_error=False会让OAuth2PasswordBearer在无法获取token时返回None,而非主动抛出认证异常,直接导致后续解码逻辑因token为None报错。请求/me时可能未正确携带Authorization头
客户端若未按照Bearer <token>的格式在请求头中传递token,OAuth2PasswordBearer无法提取到有效token,也会返回None。
解决步骤
1. 修正TokenSchema与登录接口返回格式
遵循OAuth2标准调整字段与返回内容:
class TokenSchema(BaseModel): access_token: str = Field(...) token_type: str = Field(default="bearer") # 登录接口返回修改 @app.post('/login', summary="Create access and refresh tokens for user", response_model=TokenSchema) async def login(form_data: OAuth2PasswordRequestForm = Depends()): # 原有逻辑不变... return { "access_token": create_access_token(user['email']), "token_type": "bearer" }
2. 修复get_current_user的payload解析逻辑
正确处理JWT中的sub和exp字段:
async def get_current_user(token: str = Depends(reuseable_oauth)): try: print(token) payload = jwt.decode( token, JWT_SECRET_KEY, algorithms=[ALGORITHM] ) # 提取用户标识(sub字段) user_email: str = payload.get("sub") if not user_email: raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="无效的Token凭证", headers={"WWW-Authenticate": "Bearer"}, ) # 校验token过期时间 exp_timestamp = payload.get("exp") if exp_timestamp and datetime.fromtimestamp(exp_timestamp) < datetime.now(): raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Token已过期", headers={"WWW-Authenticate": "Bearer"}, ) except(jwt.JWTError, ValidationError): raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="无法验证凭证", headers={"WWW-Authenticate": "Bearer"}, ) user: Union[dict[str, Any], None] = db.get(user_email, None) if user is None: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="未找到用户", ) return user
3. 调整OAuth2PasswordBearer的auto_error设置
将auto_error设为True,让FastAPI在无token时主动抛出认证异常:
reuseable_oauth = OAuth2PasswordBearer( tokenUrl="/login", scheme_name="JWT", auto_error=True )
4. 确保请求/me时正确携带Authorization头
客户端请求必须按格式添加请求头:
Authorization: Bearer <你的access_token>
示例curl请求:
curl -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." http://localhost:8000/me
内容的提问来源于stack exchange,提问作者heyula

