6

我有node 护照的工作知识,但它没有以下内容:

  • 生成“持久性令牌”(例如在authlogic/session/session.rb#L35
  • 为密码重置生成易腐烂的令牌
  • 记住我功能
  • 在某些模型类等上管理这些属性以进行登录/注销等。

Node.js 社区中是否有任何库解决了这个问题?如果有任何东西像Devise for Rails一样健壮(或正在变得健壮),那将是完美的,但任何解决这个令牌问题的东西都可以正常工作。

疯狂的是,很多示例都将用户存储id在会话中!

request.session['userId'] = user.get('id')

那只是要求被黑客入侵。

它应该是这样的:

require.session['persistenceToken'] = App.User.generateRandomToken()
4

3 回答 3

8

我将实施一种用于密码重置的一次性密码(又名一次性令牌)策略。鉴于 Passport 的架构,这很容易成为一个单独的模块,如果发现其他人已经实现了这样的东西,我也不会感到惊讶。

记住我,持久性令牌功能也是我想要支持的东西。最好,我也希望这也是一个单独的策略,但它可能需要一些核心支持。如果事实证明是这样,那么req.logInhttps://github.com/jaredhanson/passport/blob/master/lib/passport/http/request.js#L28)中的一些额外行应该能够覆盖它。

至于在会话中存储用户 ID,我认为没有什么大的风险,因为默认情况下,在 Connect/Express 中,会话属性完全存储在后端,并通过sid加密 cookie 中设置的唯一性进行查找。恶意用户必须同时拥有唯一的 sid 和会话秘密才能欺骗请求。

Mozilla 使用 Passport 作为其身份验证工作的一部分,将 BrowserID 连接到其他缺乏 BrowserID 支持的提供商(请参阅browserid-bigtent)。鉴于他们的要求,开发人员可以确定 Passport 满足严格的安全要求。

(最终,Passport 中的会话序列化是应用程序的责任,因此如果出于安全原因需要,可以使用随机令牌代替用户 ID。显然,如果将数据直接存储在 cookie 中,则应该这样做,但我建议这样做这是最不明智的做法。)

至于管理模型上的这些属性,Passport 被设计为完全与模型/ORM 无关。我不打算改变这个事实,因为我认为这些决定最好留给应用程序(并且由于委派了这种责任,Passport 更加灵活)。也就是说,我认为其他模块还有空间独立构建在 Passport 之上以提供此功能。

综上所述,我认为 Passport 是现有 Node.js 身份验证解决方案中最强大的。您的前三个请求将大大有助于使其变得更加如此,并且它们应该很容易完成。我很乐意合作加入这些功能,所以请随时与我联系。

最后,如果有人好奇,目前正在authinfo分支上进行一流的 API 身份验证。在此基础上,passport-http-oauth实现了 OAuth 服务器策略,可以结合oauthorize middlware 作为工具包来组装 OAuth 服务器。这还没有完全成熟,但是当它准备好时,它将成为 Passport 的另一个有效功能。

于 2012-06-26T06:42:22.020 回答
2

虽然我肯定希望在 passport.js 中看到这些功能,但它们还没有。

我创建了一个简单的随机令牌生成器以与 passport.js serilizeUser() 函数一起使用,并稍微修改了 Justen 的答案以满足我的需要。基本上,唯一的区别是如果没有设置“记住”选项,只要浏览器打开,会话就会持续。

这是我的带有随机访问令牌生成器的序列化程序。我正在使用 Mongodb 和 Mongoose,但实现应该可以很好地转换为其他系统。

基本上,我得到了时间并向它附加一个随机的 16 个字符的字符串。然后,在 serializeUser() 函数中,我检查没有其他用户具有相同的令牌(令牌应该是唯一的!)。

User.methods.generateRandomToken = function () {
  var user = this,
      chars = "_!abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890",
      token = new Date().getTime() + '_';
  for ( var x = 0; x < 16; x++ ) {
    var i = Math.floor( Math.random() * 62 );
    token += chars.charAt( i );
  }
  return token;
}; 

这是序列化程序:

passport.serializeUser( function ( user, done ) {

  var createAccessToken = function () {
    var token = user.generateRandomToken();
    app.User.findOne( { accessToken: token }, function (err, existingUser) {
      if (err) return done( err );
      if (existingUser)
        createAccessToken(); // Run the function again - the token has to be unique!
      else {
        user.set( 'accessToken', token );
        user.save( function ( err ) {
          if (err) return done( err );
          return done( null, user.get('accessToken') );
        })
      }
    });
  };

  if ( user._id ) {
    createAccessToken();
  }
});

...这是我处理“记住我”功能的中间件版本。不过,我更希望这以某种方式成为 serializeUser 函数或 passport.js 核心的一部分。

app.use( express.session( { secret: 'secret_key' } ) );
app.use( function (req, res, next) {
    if ( req.method == 'POST' && req.url == '/login' ) {
      if ( req.body.remember ) {
        req.session.cookie.maxAge = 30*24*60*60*1000; // Rememeber 'me' for 30 days
      } else {
        req.session.cookie.expires = false;
      }
    }
    next();
});
app.use( passport.initialize() );
app.use( passport.session() );

我希望这会有所帮助。我花了几个小时才弄清楚,我不太确定这是最好的方法,但它现在对我有用。

于 2012-11-27T21:39:58.717 回答
2

同时,类似以下的内容就足够了。根据需要进行调整以适合您的应用程序和所需的 cookie 持续时间。检查用户名和密码是检测登录尝试的一种俗气的方法,但它与护照一起工作得很好。

app.use(function(req, res, next) {
    if(
            typeof(req.body.username) !== "undefined"
            && typeof(req.body.password) !== "undefined"
            ) {
        if(req.body.remember == 1) {
            req.session.cookie.maxAge = 365*24*60*60*1000;
        }
        else {
            req.session.cookie.maxAge = 24*60*60*1000;
        }
    }
    next();
});
于 2012-11-25T07:30:05.357 回答