React中JWT角色授权问题:如何阻止伪造令牌进入管理员路由
我在localStorage中存储JWT,示例令牌:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiVVNFUiIsImlhdCI6MTY2MjU1NzE3Mn0.lRbHWxk8kSnTH8Okdko3cK8Nkce-0sNSeTNjQa1m33o
该令牌的Payload如下:
{ "role": "USER", "iat": 1662557172 }
我的前端有一个受保护路由,通过解码JWT并校验角色控制访问,代码如下:
if (jwt_decode(auth.user).role!=="ADMIN") { return <Navigate to="/home" /> } return children
当前问题:用户可手动创建含"ADMIN"角色的令牌,虽无法调用API,但能进入管理员路由,请问如何阻止该情况?
核心问题是前端只解码JWT的Payload内容,没有验证令牌的合法性——伪造的令牌没有后端的有效签名,只要前端不做签名校验,就会被当成有效令牌处理。要解决这个问题,必须在前端路由校验时,同步验证JWT的签名有效性,确保令牌是后端合法签发的。
具体实现步骤:
使用支持签名验证的JWT库:放弃仅解码Payload的工具,改用
jsonwebtoken或jose这类能验证签名的库。后端签发令牌时用的密钥(对称加密)或公钥(非对称加密),前端需要持有对应密钥用于校验。示例代码(以
jsonwebtoken为例):import jwt from 'jsonwebtoken'; // 注意:如果是对称加密,这里的密钥要和后端完全一致;非对称加密则用后端提供的公钥 const VALIDATION_KEY = '后端签发令牌用的密钥/公钥'; const ProtectedAdminRoute = ({ children }) => { const auth = JSON.parse(localStorage.getItem('auth')); if (!auth?.user) { return <Navigate to="/home" />; } try { // 同时完成签名验证和令牌解码 const decodedToken = jwt.verify(auth.user, VALIDATION_KEY); // 验证角色权限 if (decodedToken.role !== 'ADMIN') { return <Navigate to="/home" />; } } catch (error) { // 签名验证失败(令牌伪造、篡改或过期),直接跳转 return <Navigate to="/home" />; } return children; };自动处理令牌过期:
jwt.verify会自动校验令牌中的exp(过期时间)字段,只要后端签发令牌时设置了该字段,前端验证时就能自动拦截过期令牌。前端校验仅为体验优化,后端权限才是核心:即使前端做了签名验证,后端仍需在每个敏感API接口中重复校验令牌的签名和角色——这是防止非法访问的最后一道防线。前端校验只是避免用户进入无权限页面后才发现无法操作,提升体验而已。
另外,如果担心对称加密密钥暴露在前端代码中,建议改用非对称加密方案:后端用私钥签发令牌,前端用公钥验证签名,公钥可以安全地嵌入前端代码,不会带来安全风险。
内容的提问来源于stack exchange,提问作者Wael Ben Mustapha

