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

FastApi带Token请求后跳转触发401未授权问题的解决问询

问题描述

前端按钮点击触发的JavaScript函数:

function request_dashboard() {
    const apiUrl = 'dashboard';

    // Replace 'YOUR_BEARER_TOKEN' with your actual Bearer token.
    const bearerToken = localStorage.getItem('access_token');

    // Create headers object with Authorization header containing the Bearer token.
    const headers = {
    'Authorization': `Bearer ${bearerToken}`,
    };

    // Make the GET request using the fetch API.
    fetch(apiUrl, {
    method: 'GET',
    headers: headers,
    }).then(response => {
        window.location.href = '/dashboard';
    })
}

FastAPI路由:

@router.get("/")
def dashboard_view(request: Request, user: UserRead = Depends(auth.get_current_user)):
    return templates.TemplateResponse("dashboard.html", {"request": request})

点击按钮后的日志:

INFO:     127.0.0.1:59992 - "GET /dashboard HTTP/1.1" 307 Temporary Redirect
INFO:     127.0.0.1:59992 - "GET /dashboard/ HTTP/1.1" 200 OK
INFO:     127.0.0.1:59992 - "GET /dashboard HTTP/1.1" 307 Temporary Redirect    
INFO:     127.0.0.1:59992 - "GET /dashboard/ HTTP/1.1" 401 Unauthorized

使用fetch请求时Token认证通过且路由函数正常调用,但执行window.location.href = '/dashboard'时,新请求未携带授权头,返回401未授权错误,如何修复?


修复方案

核心原因

window.location.href发起的是浏览器原生页面跳转请求,这种请求无法手动添加自定义HTTP请求头(比如Authorization),所以后端拿不到Token导致401。而fetch属于AJAX请求,支持自定义请求头,因此能通过认证。

具体解决办法

方法1:直接用fetch获取页面内容替换当前页面(无跳转)

不需要触发页面跳转,直接通过fetch拿到dashboard页面的HTML内容,替换当前页面的DOM:

function request_dashboard() {
    const apiUrl = 'dashboard';
    const bearerToken = localStorage.getItem('access_token');
    const headers = {
        'Authorization': `Bearer ${bearerToken}`,
    };

    fetch(apiUrl, {
        method: 'GET',
        headers: headers,
    }).then(response => response.text())
      .then(html => {
          document.documentElement.innerHTML = html;
          // 可选:更新页面标题
          const titleMatch = html.match(/<title>(.*?)<\/title>/);
          if (titleMatch) document.title = titleMatch[1];
      })
}

方法2:把Token作为查询参数传递(不推荐,有安全风险)

跳转时将Token拼在URL的查询参数里,后端修改路由从参数中获取Token进行认证:

  • 前端修改:
function request_dashboard() {
    const bearerToken = localStorage.getItem('access_token');
    window.location.href = `/dashboard?token=${bearerToken}`;
}
  • 后端修改路由:
from fastapi import Query

@router.get("/")
def dashboard_view(request: Request, token: str = Query(...), user: UserRead = Depends(auth.get_current_user_with_token)):
    # 需修改auth.get_current_user_with_token函数,从token参数中验证用户身份
    return templates.TemplateResponse("dashboard.html", {"request": request})

注意:这种方式Token会暴露在URL和浏览器历史记录中,仅适合非生产环境或低敏感场景。

方法3:使用HTTP-only Cookie存储Token(推荐)

将Token存在HTTP-only Cookie中,浏览器跳转请求会自动携带Cookie,无需手动处理,安全性更高:

  • 后端修改登录接口,把access_token设置为HTTP-only Cookie:
from fastapi import Response

@router.post("/login")
def login(response: Response, login_data: LoginSchema):
    # 验证用户并生成token
    access_token = create_access_token(data={"sub": user.username})
    # 设置HTTP-only Cookie,httponly=True防止前端JS读取,避免XSS攻击
    response.set_cookie(
        key="access_token",
        value=f"Bearer {access_token}",
        httponly=True,
        secure=True,  # 生产环境开启,仅HTTPS传输
        samesite="lax"
    )
    return {"message": "登录成功"}
  • 前端删除fetch请求,直接跳转:
function request_dashboard() {
    window.location.href = '/dashboard';
}
  • 后端认证逻辑调整为从Cookie中获取Token:
def get_current_user(request: Request):
    token = request.cookies.get("access_token")
    if not token:
        raise HTTPException(status_code=401, detail="未授权")
    # 拆分Bearer前缀并验证token
    payload = jwt.decode(token.split(" ")[1], SECRET_KEY, algorithms=[ALGORITHM])
    # ... 其余用户验证逻辑

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 07:47:05