FastAPI+JavaScript用户认证问题:登录后无法访问受保护端点
核心问题根源
你当前使用的OAuth2PasswordBearer默认仅从Authorization: Bearer <token>请求头读取令牌,但后端将access_token存入了httponly Cookie——浏览器会自动在后续同域请求中携带该Cookie,但不会暴露给JS(防止XSS攻击),因此前端无法手动提取Cookie值添加到Authorization头,导致默认依赖校验失败。
解决方案:自定义认证依赖
放弃默认的OAuth2PasswordBearer,自定义依赖逻辑从请求Cookie中读取access_token并完成令牌校验。
代码示例
from fastapi import Depends, HTTPException, status, Request from jose import JWTError, jwt from pydantic import BaseModel # 你的JWT基础配置 SECRET_KEY = "your-secret-key" ALGORITHM = "HS256" class TokenData(BaseModel): username: str | None = None async def get_current_user(request: Request): # 从Cookie中获取令牌 token = request.cookies.get("access_token") if not token: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Not authenticated", headers={"WWW-Authenticate": "Bearer"}, ) try: # 解码JWT令牌 payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM]) username: str = payload.get("sub") if username is None: raise HTTPException(status_code=401, detail="Invalid token") token_data = TokenData(username=username) except JWTError: raise HTTPException(status_code=401, detail="Invalid token") # 这里可根据username查询用户数据库,返回完整用户对象 return token_data # 受保护端点使用自定义依赖 @app.get("/index") async def index(current_user: TokenData = Depends(get_current_user)): return {"message": f"Welcome {current_user.username}", "path": "/index"}
前端正确处理方式
前端无需额外操作:
- 登录请求完成后,浏览器会自动保存httponly Cookie
- 跳转
/index或发送其他同域请求时,浏览器会自动在请求中携带该Cookie - 只要后端认证依赖能从Cookie读取令牌,即可正常通过校验
最佳实践
- 坚持使用httponly Cookie:避免XSS攻击窃取令牌,安全性远高于localStorage/sessionStorage
- 强化Cookie配置:登录接口返回Cookie时,添加安全参数:
from fastapi.responses import JSONResponse @app.post("/login") async def login(form_data: OAuth2PasswordRequestForm = Depends()): # 用户名密码校验逻辑... access_token = create_access_token(data={"sub": form_data.username}) response = JSONResponse(content={"access_token": access_token, "token_type": "bearer"}) response.set_cookie( key="access_token", value=access_token, httponly=True, secure=True, # 生产环境强制开启,本地调试可暂时关闭 samesite="strict", max_age=3600 # 与令牌过期时间保持一致 ) return response - 兼容多令牌来源(可选):若需同时支持API客户端的Authorization头和浏览器Cookie,可修改依赖逻辑优先检查头信息:
async def get_current_user(request: Request): # 先检查Authorization头 auth_header = request.headers.get("Authorization") token = None if auth_header and auth_header.startswith("Bearer "): token = auth_header.split(" ")[1] else: # 再检查Cookie token = request.cookies.get("access_token") if not token: raise HTTPException(status_code=401, detail="Not authenticated") # 后续令牌校验逻辑... - 开启CSRF防护:使用Cookie认证时,需结合
fastapi-csrf-protect等工具开启CSRF防护,避免跨站请求伪造攻击
内容的提问来源于stack exchange,提问作者Karimai
相关产品推荐
相关产品推荐

