Answers:
如果您正在寻找适用于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等进行身份验证。如有必要,可插入自定义策略。
done(null,false,{ message:'Incorrect username.' })
这很糟糕,因为我们不知道所有这些参数是什么。
我想您尚未找到很多好的库的原因是,使用库进行身份验证大部分是经过精心设计的。
您正在寻找的只是会话绑定器:)具有以下内容的会话:
if login and user == xxx and pwd == xxx
then store an authenticated=true into the session
if logout destroy session
而已。
我也在使用connect,但是由于两个原因,我不使用connect-auth:
恕我直言,打破了connect-auth这一非常强大且易于阅读的洋葱圈架构。不行-我的意见:)。您可以在此处找到有关连接如何工作以及洋葱圈构想的非常好的简短文章。
如果您按照书面要求,只想对数据库或文件使用基本或http登录。Connect-auth太大。适用于OAuth 1.0,OAuth 2.0&Co之类的东西
(它是完整的。只需执行它以进行测试,但是如果要在生产中使用它,请确保使用https)(并且要符合REST-Principle的要求,您应该使用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更改。如果我需要更改任何内容,请添加评论。
看起来连接中间件的connect-auth插件正是我需要的:http : //wiki.github.com/ciaranj/connect-auth/creating-a-form-based-strategy
我使用的是express [ http://expressjs.com ],因此connect插件非常合适,因为express是connect的子类(可以-原型化)
我基本上是在寻找相同的东西。具体来说,我想要以下内容:
我最终要做的是创建自己的中间件函数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("/");
}
});
});
无论如何,这种方法主要是设计得灵活而简单。我敢肯定,有很多方法可以改善它。如果您有任何意见,我非常希望您提供反馈。
编辑:这是一个简化的示例。在生产系统中,您永远都不想以纯文本形式存储和比较密码。正如评论者所指出的那样,有一些库可以帮助管理密码安全性。
这是我的一个项目的一些基本身份验证代码。我将它与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;
}
};
几年过去了,我想介绍一下我的Express身份验证解决方案。它称为Lockit。您可以在GitHub上找到该项目,并在我的博客中找到简短的介绍。
那么与现有解决方案有什么区别?
require('lockit')
,lockit(app)
,做username
和password
。看一下例子。
有一个名为Drywall的项目,该项目使用Passport实现用户登录系统,并且还具有用户管理管理面板。如果您正在寻找一个功能全面的用户身份验证和管理系统,类似于Django所具有的功能,但适用于Node.js,就是这样。我发现这是构建需要用户身份验证和管理系统的节点应用程序的一个很好的起点。有关Passport如何工作的信息,请参见Jared Hanson的答案。
这是两个流行的Github库,用于进行节点js身份验证:
使用mongo的快速简单示例,用于为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);
}
这是使用时间戳记令牌的新身份验证库。令牌可以通过电子邮件发送或发送给用户,而无需将其存储在数据库中。它可以用于无密码身份验证或两因素身份验证。
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的作者。
轻量级,零配置的用户身份验证模块。它不需要一个正确的数据库。
https://www.npmjs.com/package/sweet-auth
它很简单:
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
}
})
omniauth
(rails)或python 等效的东西social-auth
。PHP(和其他常见的Web服务器语言)用户也可以随意添加其等效项。