前端跨域请求未携带Authorization头与Cookie的JWT认证问题
我在为已认证用户保护页面时,遇到后端无法接收Cookie和Authorization头的问题。
最初我手动在请求头里添加Authorization:
headers: { Authorization: `Bearer ${TOKEN}` }
但为了提升安全性,后端设置Cookie时启用了httpOnly: true,导致前端无法直接获取token。于是我在CORS和Axios中都配置了credentials: true,期望请求能自动携带Cookie。
现有配置
后端CORS配置:
const corsConfig = { origin: [process.env.BASE_URL], credentials: true, allowedHeaders: ["Content-Type"], }
前端Axios配置:
const api = axios.create({ withCredentials: true, baseURL: BASE_URL })
Cookie JWT认证中间件:
const cookieJwtAuth = async (req, res, next) => { try { console.log(req.headers); const [, token] = req.headers.authorization.split(" "); if (!token) { return res.status(401).json({ statusCode: 401, message: "Token not found", }); } const decodedToken = await jwt.verify(token, process.env.SECRET); if (!decodedToken.username) { return res.status(401).json({ statusCode: 401, message: "Username not found in token", }); } req.user = decodedToken; next(); } catch (err) { res.clearCookie("auth"); return res.status(400).json({ statusCode: 400, message: "Not authorized", }) } }
问题现象
通过console.log(req.headers)对比前端和Insomnia的请求头,发现明显差异:
- 前端请求头中无
cookie和authorization字段 - Insomnia请求头正常携带这两个字段,接口测试完全正常
我尝试修改CORS和Axios配置,甚至在CORS的allowedHeaders中添加了"Authentication",但问题依旧。当前核心错误是前端请求的req.headers.authorization为undefined,导致调用split方法时直接报错。
1. 修正CORS配置的核心问题
首先确认前端请求的origin(http://127.0.0.1:5500)和后端CORS配置的process.env.BASE_URL完全一致,包括协议、域名、端口(localhost和127.0.0.1在跨域规则中属于不同 origin)。
同时修正CORS配置的字段错误,补充必要的头信息:
const corsConfig = { origin: [process.env.BASE_URL], // 确认值与前端origin完全匹配 credentials: true, allowedHeaders: ["Content-Type", "Authorization"], // 修正拼写错误,添加Authorization exposedHeaders: ["Set-Cookie"], // 允许前端读取Set-Cookie响应头 }
2. 重构中间件逻辑:从Cookie而非Authorization头取token
因为Cookie设置了httpOnly: true,前端无法将token放到Authorization头中,正确做法是直接从req.cookies读取后端设置的auth Cookie(参考Insomnia请求中的auth=xxx):
const cookieJwtAuth = async (req, res, next) => { try { console.log(req.cookies); // 打印Cookie确认是否能正常获取 const token = req.cookies.auth; // 从Cookie中读取token if (!token) { return res.status(401).json({ statusCode: 401, message: "Token not found in cookie", }); } const decodedToken = await jwt.verify(token, process.env.SECRET); if (!decodedToken.username) { return res.status(401).json({ statusCode: 401, message: "Username not found in token", }); } req.user = decodedToken; next(); } catch (err) { res.clearCookie("auth"); return res.status(400).json({ statusCode: 400, message: "Not authorized", }) } }
注意:必须确保后端已安装并启用cookie-parser中间件,否则req.cookies会是undefined:
const cookieParser = require('cookie-parser'); app.use(cookieParser());
3. 确认后端Cookie设置的正确性
后端设置Cookie时,需匹配跨域场景调整参数:
res.cookie('auth', token, { httpOnly: true, secure: process.env.NODE_ENV === 'production', // 生产环境启用secure(仅HTTPS) sameSite: process.env.NODE_ENV === 'production' ? 'none' : 'lax', // 跨域场景需设为none(配合secure) maxAge: 24 * 60 * 60 * 1000, // 1天有效期 path: '/' // 确保所有路由都能携带该Cookie });
4. 前端Axios配置校验
确认Axios的withCredentials: true未被请求级配置覆盖,且baseURL与后端服务地址完全一致,避免因地址不匹配导致Cookie无法携带。
内容的提问来源于stack exchange,提问作者Eric Zardo

