JWT实现时authorization header返回undefined及token未存储问题求助
问题排查与修复方案
核心问题点
- 登录接口响应逻辑冲突:
res.json()和res.redirect()不能同时调用,Express中单次请求仅能返回一次响应,调用res.json()后响应已结束,后续跳转逻辑不生效,前端也不会自动存储返回的token。 - JWT签名参数错误:
jwt.sign(${user}, process.env.ACCESS_TOKEN)中将user对象强制转为字符串,得到的是[object Object],签名的payload完全无效,后续校验也无法拿到正确的用户信息。 - 无token存储逻辑:JWT需要前端主动存储(localStorage/sessionStorage/cookie),当前既没有前端存储token的逻辑,也没有服务端写cookie存储token的逻辑,后续请求自然不会携带Authorization头。
- 鉴权中间件逻辑缺失:当前中间件仅提取token,没有做签名校验、过期校验,也没有处理Authorization头格式错误的边界情况,鉴权逻辑完全不生效。
修复方案
1. 修复登录接口逻辑
根据项目类型二选一即可:
前后端分离模式(推荐)
删除冗余的res.redirect,只返回token,跳转和存储逻辑交给前端处理:
router.post('/index', async (req, res) => { let post = { username: req.body.username, password: req.body.password, } try { const user = await dbb('users').first('*').where({username: post.username}); if(!user || !await bcrypt.compare(post.password, user.password)) { return res.render(path.resolve('./myviews/index'), { info: 'The Username Or Password You Have Entered Does Not Match Our Records' }); } // 修正jwt签名参数,添加过期时间 const token = jwt.sign( { userId: user.id, username: user.username }, process.env.ACCESS_TOKEN, { expiresIn: '2h' } // 可自行调整有效期 ); res.json({token: token}); } catch(e) { console.log(e); res.sendStatus(500); } });
服务端渲染模式
将token存入cookie后再跳转,后续请求浏览器会自动携带cookie:
// 前面逻辑和上面一致,把res.json替换成以下代码即可 res.cookie('access_token', token, { httpOnly: true, maxAge: 2 * 60 * 60 * 1000 }); res.redirect('/home');
2. 修复鉴权中间件
补充校验逻辑和边界处理:
const jwt = require('jsonwebtoken'); function authToken(req, res, next) { // 如果用cookie存储token,改成 const token = req.cookies.access_token; 即可 const authHeader = req.headers['authorization']; if(typeof authHeader === 'undefined') return res.sendStatus(401); const bearer = authHeader.split(' '); if(bearer.length < 2) return res.sendStatus(401); const bearerToken = bearer[1]; try { const decodedUser = jwt.verify(bearerToken, process.env.ACCESS_TOKEN); req.user = decodedUser; next(); } catch (err) { // token过期、篡改都返回403 return res.sendStatus(403); } }
3. 补充前端逻辑(仅前后端分离模式需要)
前端收到token后主动存储,后续请求携带Authorization头:
// 登录请求处理 async function login(username, password) { const res = await fetch('/index', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ username, password }) }); const data = await res.json(); if(data.token) { // 存储token localStorage.setItem('access_token', data.token); // 跳转首页 location.href = '/home'; } } // 后续鉴权请求示例,所有需要鉴权的接口都用这个方法调用即可 async function fetchAuthApi(url, options = {}) { const token = localStorage.getItem('access_token'); return fetch(url, { ...options, headers: { ...options.headers, 'Authorization': `Bearer ${token}` } }) }
内容的提问来源于stack exchange,提问作者VladGershun
相关产品推荐
相关产品推荐

