如何在Express请求头中传递JWT Token?重定向带Header失败
问题分析与解决方案
为什么重定向带不了自定义请求头
浏览器处理3xx重定向时,会发起全新的GET请求,这个请求不会自动携带之前响应里设置的自定义请求头,而且res.redirect()的第二个参数是给模板渲染传值用的,根本不会放到请求头里——所以你之前的尝试都没法实现需求。
可行解决方案
方案1:用Cookie存Token(推荐,更安全)
Cookie会自动在后续所有同域请求中携带,完美适配后端验证的场景。
修改login.js的登录成功逻辑:
if(passCompare == true){ const id = userId[0].id const token = jwt.sign({ id }, process.env.SECRET, { expiresIn: 3600 }) // 设置Cookie,httpOnly防止前端JS读取,降低XSS风险 res.cookie('x-access-token', token, { httpOnly: true, maxAge: 3600 * 1000, // 和Token过期时间保持一致 secure: process.env.NODE_ENV === 'production' // 生产环境用HTTPS时开启 }) return res.status(200).redirect('/index') }
然后修改验证中间件verifyJWT,从Cookie里取Token:
verifyJWT(req, res, next){ // 从Cookie获取Token const token = req.cookies['x-access-token']; if(!token) { return res.status(400).render('login') } jwt.verify(token, process.env.SECRET, (err, decoded) =>{ if(err){ console.log(err) // 验证失败清除无效Cookie res.clearCookie('x-access-token') return res.status(300).render('login') } req.userId = decoded.id next() }) }
注意:要在server.js里引入cookie-parser中间件,否则req.cookies无法使用:
const cookieParser = require('cookie-parser') // 放在其他中间件之前 server.use(cookieParser())
方案2:渲染页面时传Token,前端存后手动携带
如果不想用Cookie,可以登录成功后直接渲染index页面,把Token传给模板,前端存在本地存储,后续AJAX请求手动加请求头。
修改login.js的登录成功逻辑:
if(passCompare == true){ const id = userId[0].id const token = jwt.sign({ id }, process.env.SECRET, { expiresIn: 3600 }) // 直接渲染index页面并传递Token return res.render('index', { token }) }
在index.ejs模板里加脚本存储Token:
<script> // 把Token存在localStorage localStorage.setItem('token', '<%= token %>'); // 后续AJAX请求示例 fetch('/your-api-path', { method: 'GET', headers: { 'x-access-token': localStorage.getItem('token') } }) </script>
这种方式适合需要前端主动控制Token的场景,但要注意XSS风险,尽量配合其他防护措施。
额外优化点
- 登录逻辑里
if(userId == '')判断有误,User.findUserId返回的是数组,空数组不等于空字符串,改成if(!userId || userId.length === 0)才对 - 错误处理可以更友好,比如用
res.render('login', { error: '邮箱无效' })代替send(new Error),让用户在页面看到提示 - 你把
bcrypt拼成了bycrypt,虽然可能是笔误,但建议修正避免依赖问题
内容的提问来源于stack exchange,提问作者Vinicius Pinto
相关产品推荐
相关产品推荐

