当使用 Pydantic 模型 TokenData 验证 JWT 时,若 payload 中的 user_id 是整数(如 14),但模型要求 id: Optional[str],会导致 ValidationError: input should be a valid string。核心解决方式是显式将 user_id 转为字符串后再传入模型。
当使用 pydantic 模型 `tokendata` 验证 jwt 时,若 payload 中的 `user_id` 是整数(如 `14`),但模型要求 `id: optional[str]`,会导致 `validationerror: input should be a valid string`。核心解决方式是显式将 `user_id` 转为字符串后再传入模型。
在 FastAPI + JWT 的认证流程中,verify_access_token 函数负责解析 token 并构造 TokenData 实例。问题根源在于:数据库或登录逻辑生成 token 时,user_id 字段被写入为整数(例如 {"user_id": 14, "exp": 1730000000}),而 schemas.TokenData 定义的 id: Optional[str] 强制要求字符串类型——Pydantic 在实例化时会严格校验,拒绝 int 值,从而抛出 string_type 错误。
✅ 正确修复方式是在创建 TokenData 前对 id 显式转换:
# oauth2.py(修改 verify_access_token 函数)
def verify_access_token(token: str, credentials_exception):
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
user_id = payload.get("user_id")
if user_id is None:
raise credentials_exception
# ✅ 关键修复:强制转为字符串,适配 TokenData.id: Optional[str]
token_data = schemas.TokenData(id=str(user_id))
except JWTError:
raise credentials_exception
return token_data
⚠️ 注意事项:
- 不要仅在类型注解处加 : str(如 id: str = payload.get("user_id")),这无法改变实际值类型,Pydantic 校验仍会失败;
- 确保生成 token 时也保持类型一致(推荐统一用字符串存储用户标识),但兼容性修复应放在验证端;
- 若后续需在业务逻辑中使用 user_id 作为整数(如数据库查询),应在 get_current_user 或路由中再做 int(token_data.id) 转换,不要在 TokenData 模型内处理业务逻辑。
? 扩展建议:更健壮的 TokenData 定义可支持多类型输入(需 Pydantic v2+):
from pydantic import BeforeValidator
from typing import Annotated
def ensure_str(v) -> str:
return str(v)
class TokenData(BaseModel):
id: Annotated[str, BeforeValidator(ensure_str)]
但针对当前 FastAPI + Pydantic v1/v2 混合环境,str(id) 显式转换是最直接、安全且向后兼容的解决方案。










