You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

基于Node.js+Express的多应用用户角色权限实现问询

实现基于应用和角色的Express权限控制方案

针对你提出的基于应用+角色的权限需求,我给你梳理一套落地性很强的实现方案,完全适配你现有JWT认证的架构:

1. 完善JWT解析中间件

首先你需要把现有的认证中间件补全,确保能正确验证JWT签名、解析出用户的角色和可访问应用列表,同时处理认证失败的情况:

const jwt = require('jsonwebtoken');
const JWT_SECRET = process.env.JWT_SECRET; // 建议从环境变量读取密钥,避免硬编码

module.exports.authenticateUser = function(req, res, next) {
  // 从请求头获取JWT(通常格式为 Authorization: Bearer <token>)
  const authHeader = req.headers.authorization;
  if (!authHeader || !authHeader.startsWith('Bearer ')) {
    return res.status(401).json({ message: '未提供有效认证令牌' });
  }

  const token = authHeader.split(' ')[1];
  try {
    // 验证并解析JWT
    const decoded = jwt.verify(token, JWT_SECRET);
    // 将解析后的核心用户信息附加到请求对象
    req.user = {
      name: decoded.name,
      role: decoded.role,
      apps: decoded.apps
    };
    next();
  } catch (err) {
    return res.status(401).json({ message: '认证令牌无效或已过期' });
  }
};

2. 定义角色-应用权限映射规则

为了让权限逻辑更清晰、易维护,我们可以把不同角色在对应应用中的允许操作定义成一个配置对象,后续调整权限直接修改配置即可:

// 建议单独放在 config/permissions.js 文件中,方便统一管理
module.exports.appRolePermissions = {
  returns: {
    editor: ['create', 'read', 'update', 'delete'], // 编辑者拥有退货应用的全部操作权限
    viewer: ['read'] // 查看者仅能读取退货数据
  },
  reviews: {
    editor: ['create', 'read', 'update'],
    viewer: ['read']
  },
  purchase: {
    admin: ['create', 'read', 'update', 'delete'],
    editor: ['create', 'read', 'update']
  }
};

3. 实现通用权限校验中间件

接下来创建一个可复用的权限校验中间件,接收目标应用和所需操作作为参数,自动校验用户是否具备对应权限:

const { appRolePermissions } = require('./config/permissions');

module.exports.checkPermission = (targetApp, requiredAction) => {
  return (req, res, next) => {
    const user = req.user;

    // 第一步:检查用户是否被授权访问目标应用
    if (!user.apps.includes(targetApp)) {
      return res.status(403).json({ message: `无权限访问${targetApp}应用` });
    }

    // 第二步:检查用户角色在目标应用中是否允许执行该操作
    const allowedActions = appRolePermissions[targetApp][user.role];
    if (!allowedActions || !allowedActions.includes(requiredAction)) {
      return res.status(403).json({ message: `当前角色无权限执行${requiredAction}操作` });
    }

    // 权限校验通过,继续执行后续路由逻辑
    next();
  };
};

4. 在路由中集成权限控制

现在你可以在各个子应用的路由里,组合使用认证中间件和权限校验中间件,实现精细化的权限拦截:

const express = require('express');
const router = express.Router();
const { authenticateUser, checkPermission } = require('./middleware/auth');
const returnsController = require('./controllers/returns');
const reviewsController = require('./controllers/reviews');
const purchaseController = require('./controllers/purchase');

// 退货应用:创建退货单(仅允许editor角色访问并执行create操作)
router.post('/returns', 
  authenticateUser, 
  checkPermission('returns', 'create'), 
  returnsController.createReturn
);

// 评论应用:更新评论(仅允许editor角色访问并执行update操作)
router.put('/reviews/:id', 
  authenticateUser, 
  checkPermission('reviews', 'update'), 
  reviewsController.updateReview
);

// 采购应用:创建采购单(无权限的用户会直接被拦截)
router.post('/purchase', 
  authenticateUser, 
  checkPermission('purchase', 'create'), 
  purchaseController.createPurchase
);

额外优化建议

  • 配置化升级:如果需要动态调整权限,可以把权限映射规则存到数据库,启动时加载或实时查询
  • JWT内容精简:确保JWT只包含必要的用户信息(角色、应用列表),避免过大影响传输性能
  • 权限缓存:如果用户权限不频繁变更,可以把权限信息缓存到Redis或内存中,减少重复计算
  • 日志记录:对权限拒绝的请求进行日志记录,方便后续排查权限相关问题

内容的提问来源于stack exchange,提问作者user6882270

火山引擎 最新活动