具有“持久性标记”function的Node.js身份validation库
我有一个节点护照的工作知识,但它没有如下的东西:
- 生成一个“持久性标记”(例如在authlogic / session / session.rb#L35中)
- 生成密码重置的易腐标记
- 记住我的function
- pipe理某些模型类的login/注销的属性等。
有没有在Node.js社区解决这个问题的库? 如果有什么像Rails的Rails那样健壮(或者说它的强大),那将是完美的,但是解决这个令牌问题的任何东西都可以起作用。
疯狂的事情是很多的例子存储在会话中的用户id
!
request.session['userId'] = user.get('id')
这只是要求被黑客入侵。
它应该是这样的:
require.session['persistenceToken'] = App.User.generateRandomToken()
用于密码重置的一次性密码(又名一次性令牌)策略是我将要实施的。 鉴于护照的架构,这可以很容易地成为一个单独的模块,并不意外发现别人已经实现了这样的事情。
记住我和持久性令牌function也是我想支持的。 最好是,我希望这是一个单独的战略,但它可能需要一些核心支持。 如果事实如此, req.logIn
( https://github.com/jaredhanson/passport/blob/master/lib/passport/http/request.js#L28 )中的一些额外的行应该能够覆盖它。
至于在会话中存储用户ID,我没有看到任何大的风险,因为在Connect / Express默认情况下,会话属性完全存储在后端,并通过在encryption的cookie中设置的唯一sid
查找。 恶意用户必须拥有唯一的sid和会话密钥才能欺骗请求。
Mozilla使用Passport作为其身份工作的一部分,以将BrowserID与其他缺乏BrowserID支持的提供者(请参阅browserid-bigtent )相连接。 考虑到他们的要求,开发人员可以确定Passport符合严格的安全要求。
(最终,Passport中的会话序列化是应用程序的责任,所以如果出于安全原因需要使用随机令牌来替代用户ID,显然这应该在将数据直接存储在cookie中的情况下完成,但是我build议这是最不明智的做法。)
至于在模型上pipe理这些属性,Passport被devise为完全模型/ ORM不可知的。 我不打算改变这个事实,因为我认为这些决定最好留给申请人(由于授权这个责任,护照更加灵活)。 也就是说,我认为还有其他模块可以独立构build在Passport之上来提供这个function。
所有这一切,我认为Passport是现有的Node.jsauthentication解决scheme中最强大的。 你的前三个要求将会使得它变得更加完善,而且应该很容易完成。 我很乐意合作获取这些function,所以不要犹豫与我联系。
最后,如果有人感到好奇,一级APIauthentication目前正在工作中,在authinfo分支上。 在此基础上, passport-http-oauth实现了OAuth服务器策略,该策略可以与oauthorize middlware结合作为工具包来组装OAuth服务器。 这还没有完全烘焙,但它准备好后,它将是护照的另一个有效function。
同时,像下面这样的东西就足够了。 根据需要进行调整以适应您的应用程序和所需的Cookie时长 检查用户名和密码是一种简单的方式来检测login尝试,但它与护照运作良好。
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(); });
虽然我一定希望在passport.js中看到这些function,但它们还不在那里。
我已经创build了一个简单的随机标记生成器来与passport.js serilizeUser()函数一起使用,并修改了Justen的答案,以适应我的需要。 基本上,唯一的区别是,如果没有设置“记住”选项,只要浏览器打开,会话就会持续。
这是我的随机访问令牌生成器的串行器。 我正在使用Mongodb和Mongoose,但实现应该转换到其他系统相当好。
基本上,我得到的时间和附加一个随机的16个字符的string。 然后,在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(); } });
…这是我处理“记住我”function的中间件版本。 不过,我宁愿将它作为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() );
我希望能有所帮助。 我花了几个小时才弄明白,我不太确定这是做到这一点的最好方法,但现在对我来说却是有效的。