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
相关产品推荐
相关产品推荐

