You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

FastAPI基于OAuth2与JWT的认证部署:如何实现浏览器自动携带token访问受保护端点

浏览器端自动携带Token的实现方案

核心问题定位

当前实现的缺口是:

  • /token POST接口仅返回JSON格式的Token,浏览器原生表单提交后无法自动存储Token
  • 现有认证逻辑仅从Authorization请求头读取Token,无法自动从浏览器存储位置获取Token
  • 登录成功后没有重定向逻辑,也没有自动携带Token的机制

具体代码修改

1. 调整Token读取逻辑

保留原有Authorization请求头读取能力(兼容接口调试、/docs页面功能),新增从Cookie读取Token的逻辑,适配浏览器自动携带Cookie的场景:

async def get_token_from_request(request: Request, oauth2_token: str = Depends(oauth2_scheme)):
    # 优先从Authorization请求头获取Token,兼容原有调试场景
    if oauth2_token:
        return oauth2_token
    # 其次从Cookie中读取Token
    return request.cookies.get("access_token")

# 替换原有get_current_user的Token依赖来源,原JWT解码、用户校验逻辑完全复用
async def get_current_user(token: str = Depends(get_token_from_request)):
    credentials_exception = HTTPException(
        status_code=status.HTTP_401_UNAUTHORIZED,
        detail="Could not validate credentials",
        headers={"WWW-Authenticate": "Bearer"},
    )
    try:
        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
        username: str = payload.get("sub")
        if username is None:
            raise credentials_exception
    except JWTError:
        raise credentials_exception
    user = get_user(fake_users_db, username=username)
    if user is None:
        raise credentials_exception
    return user

2. 调整登录接口返回逻辑

认证通过后构造重定向响应,将Token写入HttpOnly Cookie,实现认证完成后自动跳转到受保护端点的效果:

from fastapi.responses import RedirectResponse

@app.post("/token")
async def login_for_access_token(form_data: OAuth2PasswordRequestForm = Depends()):
    user = authenticate_user(fake_users_db, form_data.username, form_data.password)
    if not user:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Incorrect username or password",
        )
    access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
    access_token = create_access_token(
        data={"sub": user.username}, expires_delta=access_token_expires
    )
    # 构造303重定向响应,跳转到受保护的/view端点
    response = RedirectResponse(url="/view", status_code=status.HTTP_303_SEE_OTHER)
    # 将Token写入Cookie,设置安全属性
    response.set_cookie(
        key="access_token",
        value=access_token,
        path="/",
        max_age=ACCESS_TOKEN_EXPIRE_MINUTES * 60,
        httponly=True, # 禁止前端JS读取Cookie,防范XSS窃取
        samesite="lax",
        secure=False # 生产HTTPS环境需改为True
    )
    return response

3. 调整受保护端点渲染逻辑

将原JSON返回的受保护端点改为模板渲染形式,适配浏览器页面访问场景:

@app.get("/view", response_class=HTMLResponse)
async def read_view(request: Request, current_user: User = Depends(get_current_active_user)):
    # 将当前登录用户信息传入模板,渲染私有页面
    return templates.TemplateResponse(
        "view.html",
        {"request": request, "current_user": current_user}
    )

生产部署注意事项

  • 生产环境必须开启Cookie的secure=True属性,仅在HTTPS链路下传输Cookie,避免Token被明文窃取
  • 前后端分离跨域场景需配置跨域中间件的allow_credentials=True,同时将Cookie的samesite属性设置为none,否则浏览器不会自动携带跨域Cookie
  • JWT本身是Base64编码而非加密,不要在JWT中存储密码、手机号等敏感信息
  • 原有/docs页面的调试认证功能不受影响,仍可正常通过输入用户名密码获取Token调试接口
  • 不建议将Token存在localStorage中,前端JS可随意读取,存在较高的XSS攻击窃取风险

内容的提问来源于stack exchange,提问作者cryptoknight

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.23 16:36:02