FastAPI实现同时支持密码用户与Google用户的认证依赖注入
解决方案
核心思路
你不需要被OAuth2PasswordBearer绑定死,它本质上只是一个从请求头提取Authorization: Bearer xxx格式token的依赖,你完全可以自己控制token的解析逻辑,只要两种登录方式签发的JWT payload里带统一的用户标识和登录类型字段就行。
具体实现步骤
- 第一步:统一两种登录成功后的JWT payload结构
不管是密码登录还是Google登录,签发JWT的时候都在payload里加user_id、login_type(取值为password/google)两个固定字段,其他自定义字段按需添加即可,签名秘钥两种登录方式可以共用同一个,也可以分开,解析的时候对应判断就行。 - 第二步:自定义token提取依赖
不用纠结OAuth2PasswordBearer的tokenUrl参数,这个参数只在FastAPI自带的交互式文档里的「授权」按钮有用,不影响实际接口逻辑,你可以直接写自定义依赖提取token,示例:from fastapi import Request, HTTPException, status from typing import Optional def get_token_from_header(request: Request) -> str: auth_header = request.headers.get("Authorization") if not auth_header or not auth_header.startswith("Bearer "): raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="无效的认证凭证", headers={"WWW-Authenticate": "Bearer"}, ) return auth_header.split(" ")[1] - 第三步:实现通用的
get_logged_in_user依赖from jose import JWTError, jwt from your_module import get_user_by_id # 替换为你自己的从数据库查询用户的方法 # 替换为你自己的JWT配置 SECRET_KEY = "your-secret-key" ALGORITHM = "HS256" async def get_logged_in_user(token: str = Depends(get_token_from_header)): credentials_exception = HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="无法验证凭证", headers={"WWW-Authenticate": "Bearer"}, ) try: payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM]) user_id: str = payload.get("user_id") login_type: str = payload.get("login_type") if user_id is None or login_type not in ["password", "google"]: raise credentials_exception except JWTError: raise credentials_exception user = await get_user_by_id(user_id) if user is None: raise credentials_exception # 可把login_type挂载到user对象返回,后续业务需要可以直接调用 user.login_type = login_type return user
注意:不要在JWT里存敏感信息比如用户密码、Google的access_token,只存非敏感的标识字段即可。
可选优化
如果你还要保留FastAPI交互式文档的授权功能,不需要自定义token提取依赖,还是用OAuth2PasswordBearer,只需要把它的tokenUrl改成你密码登录的端点就行,Google登录的用户在前端拿到token之后,直接在交互式文档的授权弹窗里填token即可,完全不影响实际鉴权逻辑。
内容的提问来源于stack exchange,提问作者KOB
相关产品推荐
相关产品推荐

