FastAPI如何为后续请求添加Authorization请求头
API认证功能问题排查与解决
问题背景
我正在开发API的认证功能,实现了/login端点可以正常生成Token,但后续访问需要认证的/register端点时,请求未携带Authorization头导致认证失败。同时想知道Swagger UI的“Authorize”按钮如何自动携带Authorization头。
登录端点代码
@router.get("/login") def login(request: Request): return templates.TemplateResponse("auth/login.html", {"request": request}) @router.post("/login") def login( request: Request, username: str = Form(...), password: str = Form(...), ): errors = [] user_db = pd.read_excel('users.xlsx') user = authenticate_user(user_db=user_db, username=username, password=password) access_token = create_access_token(data={"sub": username}) response.set_cookie( key="access_token", value=f"Bearer {access_token}", httponly=True ) response.headers['Authorization'] = f"Bearer {access_token}" return response
注册端点代码
@router.get("/register") def register(request: Request, access_token: Annotated[Union[str, None], Cookie()] = None ): # print(access_token) #print(request.headers['Authorization']) return templates.TemplateResponse("auth/register.html", {"request": request}) @router.post("/register") def register( request: Request, current_user: Annotated[User, Depends(get_current_active_user)], # 此处认证失败 username: str = Form(...), password: str = Form(...), password_confirm: str = Form(...), ): print(current_user) try: user = UserCreate(username=username, password=password, password_confirm=password_confirm, superuser = False) if current_user.superuser: message = crear_usuario(user=user) return JSONResponse(content={'message': message}) else: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="User should be a superuser", headers={"WWW-Authenticate": "Bearer"}, ) except ValidationError as e: errors_list = json.loads(e.json()) for item in errors_list: errors.append(item.get("loc")[0] + ": " + item.get("msg")) return templates.TemplateResponse( "auth/register.html", {"request": request, "errors": errors} )
解决方案
一、普通用户访问时自动携带Authorization头
当前登录后Token存在httponly Cookie中,但浏览器默认不会自动将Cookie里的Token放入Authorization头,可通过两种方式解决:
- 修改认证依赖,支持从Cookie提取Token
调整get_current_active_user的实现,让它同时支持从Cookie和Authorization头获取Token:
def get_current_active_user( access_token: Annotated[Union[str, None], Cookie()] = None, token: Annotated[str, Depends(oauth2_scheme)] = None ): # 优先读取Cookie中的Token if access_token: # 移除Bearer前缀(如果存在) token = access_token.split(" ")[1] if access_token.startswith("Bearer ") else access_token # 原有Token解析逻辑 try: payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM]) username: str = payload.get("sub") if username is None: raise HTTPException(status_code=401, detail="Could not validate credentials") token_data = TokenData(username=username) except JWTError: raise HTTPException(status_code=401, detail="Could not validate credentials") # 获取并验证用户状态 user = get_user(user_db, username=token_data.username) if user is None: raise HTTPException(status_code=404, detail="User not found") if not user.active: raise HTTPException(status_code=400, detail="Inactive user") return user
- 前端请求拦截自动添加请求头
如果前端用JS发起请求(如axios、fetch),可通过拦截器自动从Cookie取Token并添加到请求头:
// 从Cookie提取Token function getCookie(name) { let value = "; " + document.cookie; let parts = value.split("; " + name + "="); if (parts.length === 2) return parts.pop().split(";").shift(); } // Axios请求拦截器示例 axios.interceptors.request.use(config => { const token = getCookie('access_token'); if (token) { config.headers.Authorization = token; } return config; });
二、配置Swagger UI让Authorize按钮自动携带Token
FastAPI默认集成Swagger UI,按以下步骤配置即可让按钮生效:
- 定义OAuth2安全方案与API元信息
from fastapi import FastAPI from fastapi.security import OAuth2PasswordBearer from pydantic import BaseModel # 定义Token响应模型 class Token(BaseModel): access_token: str token_type: str # 配置OAuth2认证 oauth2_scheme = OAuth2PasswordBearer(tokenUrl="login") # 初始化FastAPI时配置Swagger认证参数 app = FastAPI( title="你的API名称", version="1.0.0", swagger_ui_init_oauth={ "clientId": "api-client", # 可自定义或留空 "appName": "你的API", "usePkceWithAuthorizationCodeGrant": True } )
- 修改登录端点返回标准OAuth2响应
让/login接口返回符合规范的Token格式:
@router.post("/login", response_model=Token) def login( request: Request, username: str = Form(...), password: str = Form(...), ): errors = [] user_db = pd.read_excel('users.xlsx') user = authenticate_user(user_db=user_db, username=username, password=password) access_token = create_access_token(data={"sub": username}) # 设置Cookie并返回标准Token响应 response = JSONResponse(content={"access_token": access_token, "token_type": "bearer"}) response.set_cookie( key="access_token", value=f"Bearer {access_token}", httponly=True ) return response
- 使用Authorize按钮
启动API后访问/docs路径,点击“Authorize”按钮,输入用户名密码(或直接粘贴Token选择Bearer类型),确认后所有接口请求都会自动带上Authorization: Bearer <token>头。
内容的提问来源于stack exchange,提问作者Juan C
相关产品推荐
相关产品推荐

