登录后签发JWT但中间件无法获取Authorization请求头问题
问题描述
实现登录接口后,登录成功会签发JWT并返回用户信息,但在JWT验证中间件中,req.headers['authorization']始终为undefined,打印整个req.headers也找不到该字段,导致无法完成Token验证。
原登录接口代码
const login = require("express").Router(); const signUpTemplate = require('../src/Backend/SignupModel') const bcrypt = require('bcrypt') const jwt = require('jsonwebtoken'); login.post("/login", async function (request, response) { try{ const {Email,password} = request.body console.log({Email,password}); console.log('before finding'); signUpTemplate.findOne({Email:Email}).then(async (user) => { if(!user){ console.log('found user'); console.log('username/password is not exist'); response.status(400).send({msg:"username/password is not exist"}) } else{ if(await bcrypt.compare(password, user.password)){ const token = jwt.sign( { user_id: user.id, Email }, process.env.TOKEN_KEY, { expiresIn: "2h", } ); user.token = token; response.status(200).json(user); } else{ console.log('username/password is not exist'); response.status(400).send({msg:"username/password is not exist"}) } } }) } catch(e){ console.error(e); } }); module.exports = login;
原JWT验证中间件代码
const verifyJwt = (req,res,next) => { console.log('entered middle'); console.log(req.headers); console.log(req.headers['authorization']); // const authHeader = req.headers['authorization']; // if (!authHeader) return res.sendStatus(401); return res.status(200).send('test works'); } module.exports = verifyJwt
可能原因与解决方法
1. 前端未正确携带Authorization头
这是最常见的问题,登录成功后前端必须将Token以Bearer <token>的格式放在请求头的Authorization字段中发送。
示例(Axios):
axios.get('/protected-api', { headers: { 'Authorization': `Bearer ${登录返回的token}` } })
2. 跨域(CORS)配置缺失
如果前后端跨域,后端未配置允许携带自定义头,浏览器会拦截Authorization头,导致后端接收不到。
在Express中配置CORS:
const cors = require('cors'); app.use(cors({ origin: '你的前端域名', // 例如http://localhost:3000 allowedHeaders: ['Authorization', 'Content-Type'], credentials: true }));
3. Express中间件顺序错误
验证中间件必须在express.json()等请求体解析中间件之后挂载,否则可能导致头信息未被正确解析。同时要确保中间件应用到需要验证的路由上:
const express = require('express'); const app = express(); const verifyJwt = require('./verifyJwt'); const loginRouter = require('./login'); // 先解析请求体 app.use(express.json()); // 挂载登录路由 app.use('/api/auth', loginRouter); // 对需要验证的路由应用中间件 app.use('/api/protected', verifyJwt, (req, res) => { res.send('访问受保护资源成功'); });
4. 头字段大小写兼容问题
Node.js的req.headers会自动将所有请求头转为小写,因此直接使用req.headers.authorization更稳妥,避免大小写不一致的问题:
const verifyJwt = (req,res,next) => { console.log('entered middle'); console.log(req.headers); const authHeader = req.headers.authorization; if (!authHeader) return res.sendStatus(401); // 提取Token(注意Bearer与Token之间的空格) const token = authHeader.split(' ')[1]; // 执行JWT验证逻辑 jwt.verify(token, process.env.TOKEN_KEY, (err, decoded) => { if (err) return res.sendStatus(403); req.user = decoded; next(); }); }
额外:修复登录接口的异步逻辑问题
原登录接口混合使用async/await和.then(),易导致潜在错误,建议统一使用async/await:
login.post("/login", async function (request, response) { try{ const { Email, password } = request.body; console.log({ Email, password }); const user = await signUpTemplate.findOne({ Email: Email }); if(!user){ console.log('用户不存在'); return response.status(400).send({ msg: "用户名/密码不存在" }); } const isPasswordMatch = await bcrypt.compare(password, user.password); if (isPasswordMatch) { const token = jwt.sign( { user_id: user.id, Email }, process.env.TOKEN_KEY, { expiresIn: "2h" } ); user.token = token; return response.status(200).json(user); } else { console.log('密码不匹配'); return response.status(400).send({ msg: "用户名/密码不存在" }); } } catch(e) { console.error(e); return response.status(500).send({ msg: "服务器内部错误" }); } });
内容的提问来源于stack exchange,提问作者Amit Hadad
相关产品推荐
相关产品推荐

