node.js是否有任何现有的用户身份验证库?特别是我正在寻找可以为用户进行密码身份验证的东西(使用自定义后端身份验证数据库),并将该用户与会话相关联.
在我写一个auth库之前,我想我会看看人们是否知道现有的库.通过谷歌搜索找不到任何明显的东西.
-Shreyas
如果您正在寻找Connect或Express的身份验证框架,Passport值得研究:https://github.com/jaredhanson/passport
(披露:我是Passport的开发者)
我在调查了connect-auth和everyauth后开发了Passport.虽然它们都是很棒的模块,但它们并不适合我的需求.我想要的东西更轻盈,不引人注目.
Passport被分解为单独的模块,因此您可以选择仅使用您需要的内容(仅在必要时使用OAuth).Passport也不会在您的应用程序中安装任何路由,使您可以灵活地决定何时何地进行身份验证,并可以通过挂钩来控制身份验证成功或失败时发生的情况.
例如,以下是设置基于表单(用户名和密码)身份验证的两步过程:
passport.use(new LocalStrategy( function(username, password, done) { // Find the user from your DB (MongoDB, CouchDB, other...) User.findOne({ username: username, password: password }, function (err, user) { done(err, user); }); } )); app.post('/login', passport.authenticate('local', { failureRedirect: '/login' }), function(req, res) { // Authentication successful. Redirect home. res.redirect('/'); });
其他策略可通过Facebook,Twitter等进行身份验证.如有必要,可以插入自定义策略.
我想你没有找到很多好的库的原因是使用库进行身份验证主要是过度设计的.
您正在寻找的只是一个会话活页夹:)一个会话:
if login and user == xxx and pwd == xxx then store an authenticated=true into the session if logout destroy session
而已.
我正在使用连接但我不使用connect-auth有两个原因:
恕我直言打破connect-auth非常强大且易于阅读的洋葱圈连接架构.禁止 - 我的意见:).你可以找到关于如何连接工作非常好,短文章和洋葱圈的想法在这里.
如果你 - 正如所写 - 只想使用数据库或文件的基本或http登录.Connect-auth太大了.对于像OAuth 1.0,OAuth 2.0&Co这样的东西更多
(它是完整的.只需执行它进行测试,但如果你想在生产中使用它,请确保使用https)(并且要符合REST原则,你应该使用POST-Request而不是GET-Request b/c你改变了一个州:)
var connect = require('connect');
var urlparser = require('url');
var authCheck = function (req, res, next) {
url = req.urlp = urlparser.parse(req.url, true);
// ####
// Logout
if ( url.pathname == "/logout" ) {
req.session.destroy();
}
// ####
// Is User already validated?
if (req.session && req.session.auth == true) {
next(); // stop here and pass to the next onion ring of connect
return;
}
// ########
// Auth - Replace this example with your Database, Auth-File or other things
// If Database, you need a Async callback...
if ( url.pathname == "/login" &&
url.query.name == "max" &&
url.query.pwd == "herewego" ) {
req.session.auth = true;
next();
return;
}
// ####
// This user is not authorized. Stop talking to him.
res.writeHead(403);
res.end('Sorry you are not authorized.\n\nFor a login use: /login?name=max&pwd=herewego');
return;
}
var helloWorldContent = function (req, res, next) {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('authorized. Walk around :) or use /logout to leave\n\nYou are currently at '+req.urlp.pathname);
}
var server = connect.createServer(
connect.logger({ format: ':method :url' }),
connect.cookieParser(),
connect.session({ secret: 'foobar' }),
connect.bodyParser(),
authCheck,
helloWorldContent
);
server.listen(3000);
我在一年前写了这个声明,目前没有活动节点项目.因此Express中可能存在API更改.如果我要更改任何内容,请添加评论.
Looks like the connect-auth plugin to the connect middleware is exactly what I need: http://wiki.github.com/ciaranj/connect-auth/creating-a-form-based-strategy
I'm using express [ http://expressjs.com ] so the connect plugin fits in very nicely since express is subclassed (ok - prototyped) from connect
我基本上都在寻找相同的东西.具体来说,我想要以下内容:
使用包含Connect中间件功能的express.js
"基于表单"的身份验证
精确控制对哪些路由进行身份验证
用户/密码的数据库后端
使用会话
我最终做的是创建我自己的中间件函数check_auth
,我将其作为参数传递给我想要验证的每个路由.check_auth
仅检查会话以及用户是否未登录,然后将其重定向到登录页面,如下所示:
function check_auth(req, res, next) {
// if the user isn't logged in, redirect them to a login page
if(!req.session.login) {
res.redirect("/login");
return; // the buck stops here... we do not call next(), because
// we don't want to proceed; instead we want to show a login page
}
// the user is logged in, so call next()
next();
}
然后,对于每个路由,我确保此函数作为中间件传递.例如:
app.get('/tasks', check_auth, function(req, res) {
// snip
});
最后,我们需要实际处理登录过程.这很简单:
app.get('/login', function(req, res) {
res.render("login", {layout:false});
});
app.post('/login', function(req, res) {
// here, I'm using mongoose.js to search for the user in mongodb
var user_query = UserModel.findOne({email:req.body.email}, function(err, user){
if(err) {
res.render("login", {layout:false, locals:{ error:err } });
return;
}
if(!user || user.password != req.body.password) {
res.render("login",
{layout:false,
locals:{ error:"Invalid login!", email:req.body.email }
}
);
} else {
// successful login; store the session info
req.session.login = req.body.email;
res.redirect("/");
}
});
});
无论如何,这种方法主要是为了灵活和简单.我确信有很多方法可以改进它.如果你有,我非常希望你的反馈.
编辑:这是一个简化的例子.在生产系统中,您永远不想以纯文本形式存储和比较密码.正如评论者指出的那样,有一些lib可以帮助管理密码安全性.
如果您想要第三方/社交网络登录集成,还可以查看Everyauth.
以下是我的一个项目的基本身份验证代码.我使用它与CouchDB和额外的auth数据缓存,但我剥离了该代码.
围绕您的请求处理包装身份验证方法,并为不成功的身份验证提供第二个回调.成功回调将获取用户名作为附加参数.不要忘记在故障回调中正确处理错误或丢失凭据的请求:
/** * Authenticate a request against this authentication instance. * * @param request * @param failureCallback * @param successCallback * @return */ Auth.prototype.authenticate = function(request, failureCallback, successCallback) { var requestUsername = ""; var requestPassword = ""; if (!request.headers['authorization']) { failureCallback(); } else { var auth = this._decodeBase64(request.headers['authorization']); if (auth) { requestUsername = auth.username; requestPassword = auth.password; } else { failureCallback(); } } //TODO: Query your database (don't forget to do so async) db.query( function(result) { if (result.username == requestUsername && result.password == requestPassword) { successCallback(requestUsername); } else { failureCallback(); } }); }; /** * Internal method for extracting username and password out of a Basic * Authentication header field. * * @param headerValue * @return */ Auth.prototype._decodeBase64 = function(headerValue) { var value; if (value = headerValue.match("^Basic\\s([A-Za-z0-9+/=]+)$")) { var auth = (new Buffer(value[1] || "", "base64")).toString("ascii"); return { username : auth.slice(0, auth.indexOf(':')), password : auth.slice(auth.indexOf(':') + 1, auth.length) }; } else { return null; } };