Passport.js 可选身份验证

Posted

技术标签:

【中文标题】Passport.js 可选身份验证【英文标题】:Passport.js optional authentication 【发布时间】:2014-11-06 12:25:37 【问题描述】:

是否有来自 Passport.js 的可选身份验证中间件?

假设我有一条路线,/api/users。我只想向公众提供一个用户列表,但对于经过身份验证的人,我想添加更多字段。

目前我只有一个愚蠢的自定义方法可以做同样的事情,但我想知道:

Passport.js 已经提供了这样的东西或者 我怎样才能使它成为护照的一部分,就像一个插件一样。

我的方法大致是这样的

function optionalAuth(req, res, next) 

    var authHeader = req.headers.authorization;
    var token = parseToken(authHeader); // just getting the OAuth token here
    if(!token) 

        return next();
    
    User.findOne(
        token: token
    , function(err, user) 

        if(err) 
            return res.json(401, message: 'auth expired');
        ;
        if(user) 
            req.user = user;
        
        next();
    );

然而,这对我来说似乎很愚蠢,而且在 passport-auth-strategies.js 或我认为应该存在的其他身份验证层中也不行。有什么更好的方法?

如果我找到一个令牌但它是无效的,告诉我是否做正确的事情返回 401 的奖励积分 :)

【问题讨论】:

假设您已经具备基本功能(验证用户身份),我认为您可以使用req.isAuthenticated()(这是 Passport 定义的)来检查您是否要返回额外的字段。 我不能使用 req.isAuthenticated 因为我不能把 passport.authenticate() 放在这之前。为什么?因为未经身份验证的用户会被拒绝。我没有会话,它是一个无状态 API,只是一个不记名令牌。如果我将 passport.authenticate() 放在路由中,一些用户会得到 401。我希望他们通过,只能获得有限的信息。 【参考方案1】:

现在可能会迟到,但有一个 anonymous Passport 策略可以完全实现这一点。这样,公共路由既可以进行身份​​验证,也可以不进行身份验证,但是当他们这样做时,您仍然会拥有与经过身份验证的用户关联的所有信息。在这里查看:https://github.com/jaredhanson/passport-anonymous

【讨论】:

这份工作已经晚了,但可能对以后的工作有所帮助:)【参考方案2】:

这是一个简单的 PoC:

var express       = require('express');
var app           = express();
var server        = app.listen(3012);
var passport      = require('passport');
var LocalStrategy = require('passport-local').Strategy;

app.use(passport.initialize());

passport.use(new LocalStrategy(function(username, password, done) 
  if (username === 'foo' && password === 'bar') 
    return done(null,  username : 'foo' );
  
  return done(null, false);
));

app.get('/api', function(req, res, next) 
  passport.authenticate('local', function(err, user, info) 
    var data =  hello : 'world' ;
    // Only if the user authenticated properly do we include secret data.
    if (user) 
      data.secret = '3133753CR37';
    
    return res.send(data);
  )(req, res, next);
);

它在/api 端点中“手动”调用passport.authenticate。这样,您就可以更好地控制如何处理身份验证错误(在您的情况下,这不应被视为错误,而是一种限制输出的方式)。

这是未经适当身份验证的输出:

$ curl 'localhost:3012/api?username=foo&password=wrong'
"hello":"world"

还有:

$ curl 'localhost:3012/api?username=foo&password=bar'
"hello":"world","secret":"3133753CR37"

用作中间件:

var middleware = function(req, res, next) 
  passport.authenticate('local', function(err, user, info) 
    req.authenticated = !! user;
    next();
  )(req, res, next);
;

app.get('/api', middleware, function(req, res, next) 
  var data =  hello : 'world' ;
  if (req.authenticated) 
    data.secret = '3133753CR37';
  
  return res.send(data);
);

【讨论】:

谢谢。在某种程度上它比我的尝试更好,因为它使用护照进行身份验证。但它有点笨拙,我不能把它作为中间件放在未经身份验证的路由上。但这可能可以包装成某种插件。不过我得试试。 @Zlatko 我编辑了我的答案,以提供有关如何将其变成中间件的想法。 太棒了,就是这样,比我多管闲事。

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

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

passport.js 抛出未知的身份验证策略“谷歌”

Express Sequelize 和 Passport.js 身份验证策略不起作用

没有会话的 Passport js 身份验证

Sails.js + Passport.js 通过 websockets 进行身份验证

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