如何设置浏览器Authorization头使后续请求携带服务端返回的JWT?
核心问题
- 你手动创建的
Headers对象没有绑定到任何请求上,window.location.replace触发的是浏览器原生页面跳转请求,这类导航请求的请求头由浏览器自动生成,不会携带你自定义的Authorization头。 - 你当前用EJS做服务端渲染的架构,直接用Authorization头传递JWT的方案天生不适配浏览器原生页面跳转、刷新、手动输入地址访问的场景,这些场景都没法自动携带自定义请求头。
解决方案
方案1:适配当前服务端渲染架构,改用HttpOnly Cookie存储JWT(推荐)
这种方案不需要修改现有页面跳转逻辑,安全性也比存localStorage更高:
- 先安装
cookie-parser依赖,用于服务端读取Cookie:npm install cookie-parser - 在
server.js中引入并注册cookie解析中间件:const cookieParser = require('cookie-parser') // 放在其他中间件注册的前面即可 app.use(cookieParser()) - 修改登录接口逻辑,校验通过后直接通过
Set-Cookie头把JWT写入浏览器Cookie,不要放在响应头返回给前端:// 登录接口校验账号密码通过后的逻辑 const token = 你生成JWT的逻辑 res.cookie('access_token', token, { httpOnly: true, // 禁止前端JS读取,防范XSS攻击 maxAge: 24 * 60 * 60 * 1000, // 有效期可自行调整,这里是1天 sameSite: 'strict', // 防范CSRF攻击 secure: process.env.NODE_ENV === 'production' // 生产环境HTTPS下才传输Cookie }) // 然后返回正常的响应即可 - 修改
checkToken中间件,从Cookie中读取JWT校验,不需要再读Authorization头:// checkToken中间件里的取值逻辑改成 const token = req.cookies.access_token - 简化前端
login.ejs的代码,不需要手动存token、设置请求头:const submitForm = async () => { const data = { email: $('form #email').val(), password: $('form #password').val() } try { await axios.post('/api/auth/login', data) window.location.replace("/") } catch (error) { console.log(error) } }
后续浏览器所有请求(包括页面跳转、刷新、接口请求)都会自动携带Cookie,服务端可以正常拿到JWT校验。
方案2:改为单页应用模式,所有请求走Axios
如果你不想用Cookie,可以把页面路由改成前端控制,不用原生跳转:
- 拿到JWT后给Axios设置全局请求头,后续所有Axios发送的请求都会自动携带Authorization头:
localStorage.setItem("access_token", token) axios.defaults.headers.common['Authorization'] = `Bearer ${token}` - 页面跳转用前端路由(如Vue Router、React Router)实现,不要用
window.location做原生跳转,所有页面数据都通过Axios请求拉取。
内容的提问来源于stack exchange,提问作者VHK
相关产品推荐
相关产品推荐

