使用Passport.js验证角色和身份认证

19

我希望在API中创建一些路由,根据在MongoDB中定义的用户角色来显示不同的数据。这是目前我所拥有的一部分样例代码,已经可以正常工作...

router.get('/test', passport.authenticate('bearer', {session: false}), function (req, res) {
    if (req.user.role == "premium") {
        return res.send('you can see this content');
    }
    else {
        return res.send('you can not see this content');
    }
})

然而,最终目标是向用户呈现某些内容,即使他们未登录或未获得正确角色的认证。

router.get('/test', passport.authenticate('bearer', {session: false}), function (req, res) {
    if (req.user.role == "premium") {
        return res.send('this is premium content');
    }
    else {
        // could be hit by another role, or no user at all
        return res.send([some truncated version of the premium content]);
    }
})

我本以为我会想出如何操作,但我不知道如何指定相同的路由,在请求中没有任何授权头的情况下可能会被命中。

在 Passport.js/Express 中是否可能实现这一点?


你需要自己构建分支才能实现这个功能,我相信。 - Vinz243
分叉护照存储库并添加该功能,这是您的意思吗? - user393219
1
我想这个更好。如果你在使用它的话,你应该看一下这些代码行:https://github.com/jaredhanson/passport-http-bearer/blob/master/lib/strategy.js#L89-101。 - Vinz243
我明白了,当然,肯定值得研究。然而,我认为我需要提供另一个检查器,因为在某些内容上,如果他们没有授权访问(就像默认情况下一样),我仍然想把人踢出去。 - user393219
1
然后,您修改后的护照中间件应该查看当前路由,并在匹配特定正则表达式时进行拦截。或者,路由回调仍然可以通过res.send(401)进行拦截。 - Vinz243
3个回答

14

我建议您使用HTTP状态码和错误对象,这是一种常见的API约定,它使您的API用户知道正在发生什么以及原因:

app.get('/premium-resource', function(req, res, next) {
  passport.authenticate('bearer', function(err, user) {
    if (user){
      if (user.role === 'premium'){
        return res.send(200,{userContent:'you are a premium user'});
      }else{
        return res.send(403,{
          'status': 403,
          'code': 1, // custom code that makes sense for your application
          'message': 'You are not a premium user',
          'moreInfo': 'https://myawesomeapi.io/upgrade'
        });
      }
    }else{
      return res.send(401,{
        'status': 401,
        'code': 2, // custom code that makes sense for your application
        'message': 'You are not authenticated.',
        'moreInfo': 'https://myawesomeapi.io/docs'
      });
    }
  })(req, res, next);
});

声明:我在Stormpath工作,我们对API身份验证和设计进行了深入思考,并为此主题做了一次非常好的演示:

https://stormpath.com/blog/designing-rest-json-apis/


好主意!但是,任何未登录且在其流中看到高级内容的人实际上会在其控制台中收到错误,对吗?这是一个好的通用做法吗?特别是如果Angular应用程序正在侦听错误代码并响应其他路由/模板。 - user393219
你的客户端(如 Angular 应用程序等)确实需要读取这些状态码或错误消息,并根据情况作出响应 - 如何向客户端用户展示它完全由你自己来决定 :) - robertjd

9
解决方法是限制视图中的内容,而不是路由。
router.get('/test', authenticationMiddleware, function(req, res){
    var premiumFlag = req.user.role;
    res.send('premiumontent', {role: premiumFlag});
});

premiumContent.jade

p This content is visible to all users

- if role === "premium"
    p this content is only visible to premium users

1
如果使用Jade,这是一个好的解决方案。但如果不使用Jade呢?我希望将这些路由严格限制在API上。 - user393219
1
如果你正在构建一个API,你应该编辑问题并说明,这样我们就可以提供特定于API的答案 :) - robertjd
1
玉石实在是那么普遍,可以假定它已经在NodeJS应用程序中实现了吗? - user393219
1
我猜它是Node.js中最常用的模板引擎,但无论如何,它们都足够相似,以至于可以轻松地将示例从Jade转换为任何其他模板引擎。 - takinola

3

我找到的解决方案是使用适应Passportjs.org文档的方法。

在需要返回数据的路由中,无论用户是否已登录,我都可以使用以下代码:

// Test to check for authentication
app.get('/login', function(req, res, next) {
  passport.authenticate('bearer', function(err, user, info) {
    if (user)
        // check user's role for premium or not
        if (user.role == "premium")
            return res.send('user is premium')
        else
            return res.send('user is not premium');
    else
        // return items even if no authentication is present, instead of 401 response
            return res.send('not logged in');
  })(req, res, next);
});

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接