Node.js具有“持久性令牌”功能的身份验证库

时间:2012-06-26 01:47:26

标签: javascript node.js authentication

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

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

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

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

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

这只是要求被黑客攻击。

它应该是这样的:

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

3 个答案:

答案 0 :(得分: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 auth解决方案中最强大的。你的前三个请求将会有很长的路要走,并且它们应该很容易实现。我很乐意合作获取这些功能,所以不要犹豫与我联系。

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

答案 1 :(得分: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();
});

答案 2 :(得分: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() );

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