OAuth2PasswordBearer仅提取Bearer Token,不执行认证逻辑;真正的密码校验、JWT签发与解析需由开发者实现,tokenUrl仅用于OpenAPI文档生成。

OAuth2PasswordBearer 是入口,不是认证逻辑本身
很多人以为 OAuth2PasswordBearer 会自动校验密码或签发 token,其实它只是个「请求头提取器」:它只负责从 Authorization: Bearer xxx 中取出 token 字符串,然后交给你的自定义函数处理。真正的认证(查库、验密)、授权(签 token、验签名)都得你写。
常见错误现象:401 Unauthorized 却没看到任何日志,或者 token 明明有效却总被拒绝——大概率是 OAuth2PasswordBearer 拿到了 token,但后续的 Depends(get_current_user) 函数没正确解析或抛了异常,而异常被 FastAPI 静默转成 401。
- 必须配合
Depends使用,单独声明oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")不会触发任何鉴权 -
tokenUrl参数仅用于 OpenAPI 文档生成(比如 Swagger UI 的「Authorize」按钮),和实际逻辑无关 - 若用 HTTPS 反向代理(如 Nginx),需确保
X-Forwarded-Proto正确设置,否则tokenUrl在文档里可能显示为 http
JWT 签发时必须严格控制 payload 和过期时间
JWT 不是存储任意数据的保险箱。FastAPI 场景下,payload 至少要包含 sub(通常为用户 ID 或 username),且必须带 exp 声明。漏掉 exp 会导致 token 永不过期,这是生产环境高频漏洞。
示例中容易踩的坑:datetime.utcnow() 没带时区,导致在某些系统(如 Docker 容器默认 UTC)上解析失败;SECRET_KEY 硬编码在代码里,每次部署都要手动改;ALGORITHM 用 HS256 就够用,别盲目上 RS256 增加运维复杂度。
立即学习“Python免费学习笔记(深入)”;
- 用
datetime.now(timezone.utc)替代datetime.utcnow(),避免时区歧义 -
SECRET_KEY必须从环境变量读取,推荐用os.getenv("SECRET_KEY")并做非空校验 - access token 过期时间建议 ≤30 分钟,refresh token 单独签发、存服务端(如 Redis)更安全
verify_password 和 hash_password 必须用 passlib[bcrypt]
直接用 hashlib.sha256 或自己拼 salt 加密密码是严重错误。bcrypt 是目前 Python 生态最成熟、抗暴力破解能力最强的密码哈希方案,passlib 封装了其全部细节,包括自动生成 salt、验证时自动提取 salt。
常见错误现象:注册时密码能存,但登录时 verify_password(plain, hashed) 总返回 False——八成是用了不同版本的 CryptContext,或者哈希字符串被截断(比如数据库字段长度不够 60 字符)。
- 初始化必须用
CryptContext(schemes=["bcrypt"], deprecated="auto"),别删掉deprecated="auto" - 哈希结果是字符串,长度固定约 60 字符,数据库字段至少设为
VARCHAR(128) - 不要在
verify_password外层加 try/except 捕获ValueError,passlib 会自己处理格式错误
get_current_user 依赖里别漏掉 token 解析后的异常处理
这个函数是整个鉴权链路的守门人。它要完成三件事:解析 JWT、验证签名和过期时间、查用户信息。任一环节失败都必须明确 raise HTTPException(status_code=401),不能静默返回 None 或让下游报 500。
最容易被忽略的是:JWT 解析成功但用户不存在(比如用户被删除),此时应返回 401 还是 404?按 OAuth2 规范,应统一返回 401,因为客户端无法区分“token 无效”和“用户不存在”,二者都属于认证失败。
- 用
jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])解析,别用jwt.get_unverified_claims - 捕获
JWTError、ExpiredSignatureError、InvalidSignatureError等具体异常,统一转为 401 - 查库后发现用户不存在,也 raise
HTTPException(401, "Invalid authentication credentials")


















