如何转发请求头JWT并与Cookie中JWT对比完成用户身份认证?
问题修复方案
一、后端侧修复
1. 前置依赖校验
确保已安装并注册cookie-parser中间件,否则Node服务无法读取请求携带的Cookie:
npm i cookie-parser
在入口文件app.js中注册中间件:
const cookieParser = require('cookie-parser'); app.use(cookieParser());
2. 修改权限校验中间件
你当前的protect中间件仅读取请求头的Authorization字段,未读取Cookie中的JWT,也没有做两者的一致性校验,修改对应逻辑:
exports.protect = catchAsync(async (req, res, next) => { // 1) 同时从请求头和Cookie获取token let headerToken, cookieToken, token; if (req.headers.authorization && req.headers.authorization.startsWith('Bearer')) { headerToken = req.headers.authorization.split(' ')[1]; token = headerToken; } // 新增读取Cookie中的jwt if (req.cookies.jwt) { cookieToken = req.cookies.jwt; // 若请求头无token则默认用Cookie的token if (!token) token = cookieToken; } // 你要求的请求头与Cookie token一致性校验 if (headerToken && cookieToken && headerToken !== cookieToken) { return next(new AppError('身份凭证不一致,请重新登录', 401)); } if (!token) { return next( new AppError('You are not logged in! Please log in to get access.', 401) ); } // 后续原有校验逻辑保持不变 // 2) Verification token const decoded = await promisify(jwt.verify)( token, 'my-ultra-secure-and-ultra-long-secret' ); // 3) Check if user still exists const currentUser = await User.findById(decoded.id); if (!currentUser) { return next( new AppError( 'The user belonging to this token does no longer exist.', 401 ) ); } // 4) Check if user changed password after the token was issued if (currentUser.changedPasswordAfter(decoded.iat)) { return next( new AppError('User recently changed password! Please log in again.', 401) ); } // GRANT ACCESS TO PROTECTED ROUTE req.user = currentUser; res.locals.user = currentUser; next(); });
注意:你路由中用到的
isLoggedIn中间件也要同步修改token读取逻辑,和上面保持一致。
二、前端侧修复
1. 持久化登录状态解决刷新丢失问题
Redux的状态存储在内存中,页面刷新会被清空,需要将登录信息持久化到本地存储,修改登录action:
export const login = (email, password) => async dispatch => { try { dispatch({ type: USER_LOGIN_REQUEST, }); const config = { headers: { "Content-Type": "application/json", }, }; const { data } = await axios.post( '/api/v1/users/login', { email, password }, config ); dispatch({ type: USER_LOGIN_SUCCESS, payload: data, }); // 新增:持久化存储登录信息到localStorage localStorage.setItem('userInfo', JSON.stringify(data)); } catch (error) { dispatch({ type: USER_LOGIN_FAIL, payload: error.response && error.response.data.message ? error.response.data.message : error.message, }); } };
2. 全局配置请求头自动携带token
新增axios请求拦截器,所有请求自动在请求头带上JWT,不需要每次请求单独配置:
// 在项目公共axios配置文件中添加 import axios from 'axios'; // 跨域请求携带Cookie必须开启该配置 axios.defaults.withCredentials = true; axios.interceptors.request.use( config => { const userInfo = JSON.parse(localStorage.getItem('userInfo')); if (userInfo?.token) { config.headers.Authorization = `Bearer ${userInfo.token}`; } return config; }, error => Promise.reject(error) );
3. 应用初始化恢复登录状态
在入口文件App.js中添加初始化逻辑,页面刷新后从本地存储读取登录信息恢复Redux状态:
import { useDispatch } from 'react-redux'; function App() { const dispatch = useDispatch(); useEffect(() => { const userInfo = JSON.parse(localStorage.getItem('userInfo')); if (userInfo) { dispatch({ type: USER_LOGIN_SUCCESS, payload: userInfo }); } }, [dispatch]) // 其余App逻辑保持不变 }
4. 可选:登出逻辑补充
登出时需要同步清空本地存储和后端Cookie:
export const logout = () => dispatch => { localStorage.removeItem('userInfo'); dispatch({ type: USER_LOGOUT }); // 调用后端登出接口清空jwt Cookie axios.get('/api/v1/users/logout'); };
内容的提问来源于stack exchange,提问作者valkkorn
相关产品推荐
相关产品推荐

