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

Posted

技术标签:

【中文标题】使用 Passport.js 验证角色和身份验证【英文标题】:Verifying roles & authentication with Passport.js 【发布时间】:2015-01-09 19:00:25 【问题描述】:

所以我想在 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]);
    
)

我想我会弄清楚如何工作,但我不知道如何指定在请求中没有任何 Authorization 标头的情况下可能会被命中的相同路由。

这在 Passport.js/Express 中可行吗?

【问题讨论】:

我相信你必须建立自己的分叉才能允许这样做 fork 护照回购并添加功能,你的意思是这样吗? 我认为是这个。如果你正在使用它。 github.com/jaredhanson/passport-http-bearer。你应该看看这些行是github.com/jaredhanson/passport-http-bearer/blob/master/lib/… 我明白了,当然,绝对值得研究。但是我认为我需要提供另一个检查器,因为在某些内容上,如果他们没有授权,我仍然想将他们踢出去(就像默认情况下一样)。 那么您的护照中间件的修改版本也许应该查看当前路由并在它匹配特定的正则表达式时踢。或者路由回调仍然可以通过 res.send(401) 【参考方案1】:

解决方案是限制视图中的内容而不是路由。

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

【讨论】:

如果使用翡翠,这是一个很好的解决方案,当然。如果我不使用 Jade 怎么办?我想将这些路由严格保留在 API 上。 如果您正在构建 API,您应该编辑问题以这样说,这样我们就可以提供 API 特定的答案 :) Jade 真的有那么普遍地认为它是在 NodeJS 应用程序中实现的吗? 我猜它是 nodejs 最常用的模板引擎,但不管它们都足够相似,示例可以很容易地从 Jade 转换为任何其他模板引擎。【参考方案2】:

我找到的解决方案是使用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);
);

【讨论】:

【参考方案3】:

我建议您使用 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 应用程序正在侦听错误代码并使用其他路由/模板进行响应? 您的客户端(Angular 应用程序等)确实需要阅读这些状态代码或错误消息并做出相应的响应——您如何将其展示给客户端的用户......这完全取决于您 :)

以上是关于使用 Passport.js 验证角色和身份验证的主要内容,如果未能解决你的问题,请参考以下文章

没有会话的 Passport js 身份验证

使用 MongoDB Atlas 和 Passport.js 设置 Facebook 身份验证

Node.js - JWT、API:如何实现多个 Passport.js 身份验证中间件?

使用 Passport.js、express-session 和 express-mysql-session 进行用户身份验证

Passport.js 身份验证失败时发回 JSON 响应

passport.js 使用sails.js 验证弹出窗口