node.js的用户认证库?

是否存在node.js的现有用户身份验证库?特别是,我正在寻找可以为用户(使用自定义后端auth DB)进行密码身份验证的东西,并将该用户与会话关联。

在我编写一个认证库之前,我想看看人们是否知道现有的库。在谷歌上找不到明显的东西。

-Shreyas

106945 次浏览

下面是我的一个项目中的一些基本身份验证代码。我使用它来对付CouchDB和额外的认证数据缓存,但我剥离了这些代码。

在请求处理周围包装一个身份验证方法,并为身份验证不成功提供第二个回调。成功回调将获得用户名作为附加参数。不要忘记在失败回调中正确处理错误或缺少凭据的请求:

/**
* 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;
}


};

看起来connect-auth插件连接中间件正是我所需要的

我使用的是express [http://expressjs.com],所以连接插件非常适合,因为express是连接的子类(好吧-原型)

会话+ If

我想,您没有找到很多好的库的原因是,使用库进行身份验证在很大程度上是过度设计的。

你要找的只是一个会话绑定器:)一个会话:

if login and user == xxx and pwd == xxx
then store an authenticated=true into the session
if logout destroy session

这是它。


我不同意你认为connect-auth插件是正确的选择的结论。

我也使用连接,但我没有使用连接认证,原因有两个:

    IMHO打破了connect-auth非常强大且易于阅读的洋葱环架构。不去——我的观点:)。 你可以找到一篇关于connect如何工作和洋葱圈想法的非常好的简短文章在这里.

  1. 如果你——如前所述——只是想使用数据库或文件的基本或http登录。Connect-auth太大了。它更多的是用于OAuth 1.0, OAuth 2.0 &有限公司


使用connect进行非常简单的身份验证

< p >(它是完整的。只是执行测试,但如果你想在生产中使用它,请确保使用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);

请注意

我在一年多前写了这个声明,目前没有活动节点项目。可能会有API-Changes in Express。如果我需要修改什么,请加上评论。

如果你想要第三方/社交网络登录集成,也可以看看everyauth

如果你正在寻找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等进行身份验证还可以使用其他策略。如果需要,可以插入自定义策略。

我基本上也在找同样的东西。具体来说,我想要的是:

  1. 使用express.js,它包装了Connect的中间件功能
  2. “基于表单的”身份验证
  3. 对哪些路由进行验证的粒度控制
  4. 用户/密码的数据库后端
  5. 使用会话

我最终做的是创建我自己的中间件函数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("/");
}
});
});

无论如何,这种方法主要被设计为灵活和简单。我相信有很多方法可以改善它。如果你有任何建议,我非常希望得到你的反馈。

编辑:这是一个简化的例子。在生产系统中,您永远不希望存储&比较纯文本中的密码。正如一位评论者指出的那样,有一些库可以帮助管理密码安全。

有一个名为干墙的项目,它使用护照实现了一个用户登录系统,并且还有一个用户管理面板。如果你正在寻找一个功能齐全的用户认证和管理系统,类似于Django提供的Node.js,这就是它。我发现,对于构建一个需要用户身份验证和管理系统的节点应用程序来说,这是一个非常好的起点。有关Passport如何工作的信息,请参见Jared Hanson的回答

几年过去了,我想介绍我的Express身份验证解决方案。它叫做Lockit。你可以在GitHub上找到这个项目,在我的博客上有一个简短的介绍。

那么与现有的解决方案有什么不同呢?

  • 易于使用:设置你的DB, npm install, require('lockit')lockit(app),完成
  • 路由已经内置(/注册,/登录,/忘记密码等)
  • 视图已经内置(基于Bootstrap,但您可以轻松使用自己的视图)
  • 它支持AngularJS / Ember.js单页面应用的JSON通信
  • 它不支持OAuth和OpenID。只有usernamepassword
  • 它与多个数据库(CouchDB, MongoDB, SQL)开箱即用
  • 它有测试(我找不到任何石膏板的测试)
  • 它是主动维护的(与每个auth相比)
  • 邮件验证和忘记密码流程(发送邮件时带token, Passport不支持)
  • 模块化:只使用您需要的
  • 灵活性:定制所有的东西

看一下例子

使用mongo的简单示例,用于为ie Angular客户端提供用户认证的API

在app.js

var express = require('express');
var MongoStore = require('connect-mongo')(express);


// ...


app.use(express.cookieParser());
// obviously change db settings to suit
app.use(express.session({
secret: 'blah1234',
store: new MongoStore({
db: 'dbname',
host: 'localhost',
port: 27017
})
}));


app.use(app.router);

对于你的路线是这样的:

// (mongo connection stuff)


exports.login = function(req, res) {


var email = req.body.email;
// use bcrypt in production for password hashing
var password = req.body.password;


db.collection('users', function(err, collection) {
collection.findOne({'email': email, 'password': password}, function(err, user) {
if (err) {
res.send(500);
} else {
if(user !== null) {
req.session.user = user;
res.send(200);
} else {
res.send(401);
}
}
});
});
};

然后在你需要认证的路由中,你可以检查用户会话:

if (!req.session.user) {
res.send(403);
}

下面是两个流行的用于node js身份验证的Github库:

https://github.com/jaredhanson/passport(易受暗示)

https://nodejsmodules.org/pkg/everyauth

另一个不同的身份验证是passdless,一个用于express的基于令牌的身份验证模块,它绕过了密码[1]的固有问题。它实现起来很快,不需要太多表单,并且为普通用户提供了更好的安全性(完全披露:我是作者)。

[1]: 密码过时

下面是一个使用时间戳令牌的新身份验证库。令牌可以通过电子邮件或短信发送给用户,而不需要将它们存储在数据库中。它可以用于无密码身份验证或双因素身份验证。

https://github.com/vote539/easy-no-password

披露:我是这个库的开发者。

如果您需要使用Microsoft Windows用户帐户进行SSO(单点登录)身份验证。你可以尝试https://github.com/jlguenego/node-expose-sspi

它会给你一个req.sso对象,其中包含所有客户端用户信息(登录名、显示名、sid、组)。

const express = require("express");
const { sso, sspi } = require("node-expose-sspi");


sso.config.debug = false;


const app = express();


app.use(sso.auth());


app.use((req, res, next) => {
res.json({
sso: req.sso
});
});


app.listen(3000, () => console.log("Server started on port 3000"));

声明:我是node-expose-sspi的作者。

slim-auth

轻量级、零配置的用户认证模块。它不需要单独的数据库。

https://www.npmjs.com/package/slimauth

很简单:

app.get('/private-page', (req, res) => {


if (req.user.isAuthorized) {
// user is logged in! send the requested page
// you can access req.user.email
}
else {
// user not logged in. redirect to login page
}
})

关于手摇方法,要注意一点:

我很失望地看到,本文中建议的一些代码示例并不能防止会话固定或定时攻击等基本身份验证漏洞。

与这里的一些建议相反,身份验证是简单的,处理解决方案并不总是琐碎的。我推荐passportjsbcrypt

但是,如果你决定要处理一个解决方案,可以看看Express js提供的示例以获得灵感。

祝你好运。