You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Express路由中添加授权?多用户路由权限配置方法

嘿,这个权限控制需求在Express里用中间件就能轻松搞定,我给你捋一遍具体实现步骤,都是项目里常用的方案:

1. 先定义清晰的权限规则

首先我们把用户角色和允许访问的路由前缀对应起来,还有公共路由(比如/login)单独列出来,后续维护起来会很方便:

// 可以放在单独的config/permissions.js文件里
const rolePermissions = {
  A: ['/blogs', '/news'], // A用户能访问/blogs和/news下的所有子路由
  B: ['/profile'],        // B用户只能访问/profile下的所有子路由
  public: ['/login']      // 所有用户都能访问的公共路由
};

module.exports = rolePermissions;

2. 编写权限校验中间件

这是核心部分,中间件会在请求到达具体路由前,检查用户的登录状态和权限:

// middleware/checkPermission.js
const rolePermissions = require('../config/permissions');

const checkPermission = (req, res, next) => {
  // 第一步:检查是否是公共路由,直接放行
  const isPublic = rolePermissions.public.some(route => req.path.startsWith(route));
  if (isPublic) {
    return next();
  }

  // 第二步:检查用户是否已登录(这里假设登录后用户信息存在req.user中,比如通过session或JWT)
  if (!req.user) {
    return res.status(401).send('请先登录后再访问');
  }

  // 第三步:根据用户角色获取允许的路由列表
  const allowedRoutes = rolePermissions[req.user.role];
  if (!allowedRoutes) {
    return res.status(403).send('您没有权限访问任何资源');
  }

  // 第四步:验证当前请求路径是否在允许的范围内(支持子路由匹配,比如/blogs/new、/blogs/:id/edit都属于/blogs前缀)
  const hasAccess = allowedRoutes.some(route => req.path.startsWith(route));
  if (hasAccess) {
    next(); // 权限通过,继续执行后续路由
  } else {
    res.status(403).send('您没有权限访问该资源');
  }
};

module.exports = checkPermission;

3. 处理登录逻辑(获取用户角色)

登录路由不需要权限校验,登录成功后我们要把用户的角色信息存储起来,方便后续中间件获取。这里分两种常见场景:

场景1:使用Session存储用户信息

先安装express-session:npm install express-session
然后在登录路由里设置session:

// routes/login.js
const express = require('express');
const router = express.Router();

router.post('/login', (req, res) => {
  // 这里替换成你的实际用户验证逻辑(比如从数据库查用户)
  const { username, password } = req.body;
  let user;
  if (username === 'A' && password === 'passwordA') {
    user = { id: 1, role: 'A' };
  } else if (username === 'B' && password === 'passwordB') {
    user = { id: 2, role: 'B' };
  } else {
    return res.status(400).send('用户名或密码错误');
  }

  // 将用户信息存入session
  req.session.user = user;
  res.send(`欢迎${user.role}用户登录`);
});

module.exports = router;

场景2:使用JWT令牌

如果是前后端分离项目,更推荐用JWT。先安装jsonwebtoken:npm install jsonwebtoken
先写一个JWT验证中间件:

// middleware/authenticateToken.js
const jwt = require('jsonwebtoken');

const authenticateToken = (req, res, next) => {
  const authHeader = req.headers['authorization'];
  // 从请求头中获取Bearer令牌
  const token = authHeader && authHeader.split(' ')[1];

  if (!token) {
    return res.status(401).send('请提供访问令牌');
  }

  // 验证令牌并解析用户信息
  jwt.verify(token, 'your-jwt-secret-key', (err, user) => {
    if (err) {
      return res.status(403).send('令牌无效');
    }
    req.user = user;
    next();
  });
};

module.exports = authenticateToken;

然后登录路由返回JWT令牌:

// routes/login.js
const express = require('express');
const jwt = require('jsonwebtoken');
const router = express.Router();

router.post('/login', (req, res) => {
  // 同样的用户验证逻辑
  const { username, password } = req.body;
  let user;
  if (username === 'A' && password === 'passwordA') {
    user = { id: 1, role: 'A' };
  } else if (username === 'B' && password === 'passwordB') {
    user = { id: 2, role: 'B' };
  } else {
    return res.status(400).send('用户名或密码错误');
  }

  // 生成JWT令牌,有效期1小时
  const token = jwt.sign(user, 'your-jwt-secret-key', { expiresIn: '1h' });
  res.json({ token });
});

module.exports = router;

4. 挂载路由并应用中间件

最后在主文件app.js里把所有路由和中间件整合起来:

如果用Session:

const express = require('express');
const session = require('express-session');
const app = express();
const checkPermission = require('./middleware/checkPermission');
const loginRouter = require('./routes/login');
const blogRouter = require('./routes/blog');
const newsRouter = require('./routes/news');
const profileRouter = require('./routes/profile');

// 配置Session
app.use(session({
  secret: 'your-session-secret-key',
  resave: false,
  saveUninitialized: false,
  cookie: { secure: false } // 生产环境建议设为true,配合HTTPS
}));

// 解析请求体
app.use(express.json());
app.use(express.urlencoded({ extended: true }));

// 先挂载登录路由,不需要权限校验
app.use(loginRouter);

// 挂载权限校验中间件,之后的所有路由都会经过这个中间件
app.use(checkPermission);

// 挂载其他业务路由
app.use(blogRouter);
app.use(newsRouter);
app.use(profileRouter);

app.listen(3000, () => {
  console.log('服务器运行在http://localhost:3000');
});

如果用JWT:

只需要把Session的配置换成JWT验证中间件,并且把它放在权限中间件前面:

const express = require('express');
const app = express();
const authenticateToken = require('./middleware/authenticateToken');
const checkPermission = require('./middleware/checkPermission');
const loginRouter = require('./routes/login');
const blogRouter = require('./routes/blog');
const newsRouter = require('./routes/news');
const profileRouter = require('./routes/profile');

// 解析请求体
app.use(express.json());
app.use(express.urlencoded({ extended: true }));

// 挂载登录路由
app.use(loginRouter);

// 先验证JWT,再校验权限
app.use(authenticateToken);
app.use(checkPermission);

// 挂载业务路由
app.use(blogRouter);
app.use(newsRouter);
app.use(profileRouter);

app.listen(3000, () => {
  console.log('服务器运行在http://localhost:3000');
});

一些额外说明

  • 如果需要更细粒度的权限控制(比如A用户能看博客列表但不能编辑),可以把权限规则写得更具体,比如A: ['/blogs', '/blogs/new', '!/blogs/:id/edit'],然后在中间件里处理排除规则,不过当前需求按前缀匹配足够了。
  • 建议把权限规则、中间件都拆成单独文件,不要写在app.js里,这样项目结构更清晰,维护起来也方便。

内容的提问来源于stack exchange,提问作者Rifat Bin Reza

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 10:21:41