基于NodeJS+JWT的双角色(用户/代理)认证授权机制设计建议
区分用户/代理角色并实现JWT权限校验方案
1. 在JWT Payload中嵌入角色标识
生成JWT时,直接把角色类型(user或agent)写入payload,代理账号额外添加managedUserIds字段,存储其负责的用户ID列表。示例代码:
// 生成普通用户令牌 function generateUserToken(user) { return jwt.sign( { id: user.id, role: 'user', email: user.email }, process.env.JWT_SECRET, { expiresIn: '24h' } ); } // 生成代理用户令牌 function generateAgentToken(agent) { return jwt.sign( { id: agent.id, role: 'agent', email: agent.email, managedUserIds: agent.managedUserIds // 代理管辖的用户ID数组 }, process.env.JWT_SECRET, { expiresIn: '24h' } ); }
2. 编写分层的权限校验中间件
先做通用认证解析JWT,再按角色拆分专属校验逻辑:
// 通用JWT解析中间件 const authenticate = (req, res, next) => { const token = req.headers.authorization?.split(' ')[1]; if (!token) { return res.status(401).json({ message: '未提供有效令牌' }); } try { const decoded = jwt.verify(token, process.env.JWT_SECRET); req.user = decoded; next(); } catch (err) { return res.status(403).json({ message: '令牌无效或已过期' }); } }; // 校验仅普通用户可访问 const requireUserRole = (req, res, next) => { if (req.user.role !== 'user') { return res.status(403).json({ message: '仅普通用户可执行此操作' }); } next(); }; // 校验仅代理可访问 const requireAgentRole = (req, res, next) => { if (req.user.role !== 'agent') { return res.status(403).json({ message: '仅代理可执行此操作' }); } next(); };
3. 代理代操作的额外权限校验
代理代用户执行操作时,需要验证其是否有权限操作目标用户,可单独写中间件:
// 校验代理是否有权操作指定用户 const requireAgentForTargetUser = (req, res, next) => { const targetUserId = req.body.targetUserId || req.params.targetUserId; if (!targetUserId) { return res.status(400).json({ message: '需指定目标用户ID' }); } if (!req.user.managedUserIds.includes(targetUserId)) { return res.status(403).json({ message: '你无权操作该用户' }); } next(); };
4. 路由层的实际使用示例
// 普通用户自行租车接口 app.post('/api/car/rent', authenticate, requireUserRole, (req, res) => { // 业务逻辑:用req.user.id作为租车人ID res.json({ message: '租车申请提交成功', userId: req.user.id }); }); // 代理代用户租车接口 app.post('/api/agent/car/rent', authenticate, requireAgentRole, requireAgentForTargetUser, (req, res) => { // 业务逻辑:用req.body.targetUserId作为实际租车人ID res.json({ message: '代用户提交租车申请成功', targetUserId: req.body.targetUserId, agentId: req.user.id }); });
5. 注意事项
- 如果代理负责的用户列表频繁变动,建议不要把
managedUserIds存在JWT里,而是在校验时实时查询数据库,避免令牌过期前权限不一致 - JWT payload只存必要的非敏感数据,不要放密码、手机号等隐私信息
- 权限校验逻辑尽量封装在中间件,减少业务代码里的重复校验
内容的提问来源于stack exchange,提问作者Abdi mussa
相关产品推荐
相关产品推荐

