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

FastAPI JWT认证中token返回None的原因及解决办法

问题原因与解决方案

问题原因

  1. TokenSchema字段不符合OAuth2规范
    FastAPI的OAuth2PasswordBearer遵循OAuth2标准,默认要求返回的token字段为access_token,且需附带token_type(值为bearer)。你的TokenSchema定义为accesstoken(无下划线),且登录接口未返回token_type,会导致客户端无法正确识别token格式,或后续认证逻辑无法提取有效token。

  2. get_current_user中payload解析逻辑错误
    你从JWT解码后的payload中直接取token_data = payload['sub'],但sub字段通常是用户标识(如邮箱)而非包含exp的对象,后续访问token_data.exp会触发异常。再加上auto_error=False的设置,依赖会返回None而非抛出异常,最终导致token变量为None。

  3. auto_error设置不当
    auto_error=False会让OAuth2PasswordBearer在无法获取token时返回None,而非主动抛出认证异常,直接导致后续解码逻辑因token为None报错。

  4. 请求/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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 23:30:47