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

MEAN栈结合JWT实现获取当前登录用户角色并限制/admin角色访问特定接口的方法

好的,我来帮你解决这个权限控制的问题!要实现仅admin角色用户访问/special接口,我们需要分两步走:先获取当前登录用户的角色信息,再验证角色是否符合要求。下面给你两种可行的方案,你可以根据实际需求选择:


方案一:验证Token后查询数据库获取用户信息

这种方案适合不想修改现有JWT生成逻辑的场景,我们会在Token验证完成后,根据用户ID去数据库查询完整的用户信息,从中获取角色:

首先,修改你的verifyToken中间件,引入User模型并查询用户信息:

const User = require('./models/user'); // 记得引入你的User模型

function verifyToken(req, res, next) { 
  if(!req.headers.authorization) { 
    return res.status(401).send('Unauthorized request') 
  } 
  let token = req.headers.authorization.split(' ')[1] 
  if(token === 'null') { 
    return res.status(401).send('Unauthorized request') 
  } 
  try {
    let payload = jwt.verify(token, 'secretKey') 
    if(!payload) { 
      return res.status(401).send('Unauthorized request') 
    } 
    // 根据payload里的用户ID查询数据库
    User.findById(payload.subject)
      .then(user => {
        if (!user) {
          return res.status(404).send('User not found');
        }
        req.user = user; // 把用户信息挂载到req对象上,方便后续使用
        next();
      })
      .catch(err => {
        return res.status(500).send('Failed to fetch user information');
      });
  } catch (err) {
    // 处理Token过期或无效的情况
    return res.status(401).send('Invalid or expired token');
  }
}

接下来,创建一个专门的checkAdmin中间件来验证用户角色:

function checkAdmin(req, res, next) {
  // 检查当前用户角色是否为admin
  if (req.user.role !== 'admin') {
    return res.status(403).send('Forbidden: Only admin users can access this resource');
  }
  next(); // 角色验证通过,继续执行后续逻辑
}

最后,修改你的/special接口,把两个中间件都加上:

router.get('/special', verifyToken, checkAdmin, (req,res) => { 
  // 这里req.user就是当前登录的完整用户信息,你可以按需使用
  let specialEvents = [/* 你的敏感数据 */];
  res.json(specialEvents);
});

方案二:在JWT Payload中包含角色信息(更高效)

如果你想避免每次请求都查询数据库,可以在生成JWT的时候就把用户角色加入到Payload里,这样验证Token时就能直接拿到角色信息:

首先,修改你的登录接口(生成Token的地方),把角色加入Payload:

// 示例登录接口,根据你的实际代码调整
router.post('/login', (req, res) => {
  User.findOne({ email: req.body.email })
    .then(user => {
      if (!user) {
        return res.status(404).send('User not found');
      }
      // 这里记得用bcrypt等工具验证密码,不要直接明文比较!
      if (user.password !== req.body.password) { 
        return res.status(401).send('Invalid password');
      }
      // 生成Token时,把用户ID和角色都加入Payload
      let payload = { subject: user._id, role: user.role };
      let token = jwt.sign(payload, 'secretKey');
      res.json({ token });
    })
    .catch(err => {
      res.status(500).send('Login failed');
    });
});

然后修改verifyToken中间件,直接从Payload中提取角色:

function verifyToken(req, res, next) { 
  if(!req.headers.authorization) { 
    return res.status(401).send('Unauthorized request') 
  } 
  let token = req.headers.authorization.split(' ')[1] 
  if(token === 'null') { 
    return res.status(401).send('Unauthorized request') 
  } 
  try {
    let payload = jwt.verify(token, 'secretKey') 
    if(!payload) { 
      return res.status(401).send('Unauthorized request') 
    } 
    req.userId = payload.subject;
    req.userRole = payload.role; // 把角色挂载到req对象上
    next();
  } catch (err) {
    return res.status(401).send('Invalid or expired token');
  }
}

同样,创建checkAdmin中间件(这次直接用req.userRole):

function checkAdmin(req, res, next) {
  if (req.userRole !== 'admin') {
    return res.status(403).send('Forbidden: Only admin users can access this resource');
  }
  next();
}

最后更新/special接口:

router.get('/special', verifyToken, checkAdmin, (req,res) => { 
  let specialEvents = [/* 你的敏感数据 */];
  res.json(specialEvents);
});

一些重要提醒

  • 生产环境中绝对不要使用硬编码的secretKey,应该用环境变量(比如process.env.JWT_SECRET)来存储,保证安全性。
  • 密码一定要加密存储(推荐使用bcrypt),永远不要明文存在数据库里。
  • JWT的Payload是可以被解码的,所以不要把敏感信息(比如密码)放进Payload里,只能放非敏感的标识信息(比如用户ID、角色)。

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

火山引擎 最新活动