node.js的用户身份验证库?

时间:2010-08-16 22:44:11

标签: authentication node.js serverside-javascript

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

在我写一个auth库之前,我想我会看看人们是否知道现有的库。通过谷歌搜索找不到任何明显的东西。

-Shreyas

15 个答案:

答案 0 :(得分:229)

如果您正在寻找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 :(得分:88)

会话+如果

我猜你没有找到很多好的库的原因是使用库进行身份验证主要是过度设计的。

您正在寻找的只是一个会话活页夹:)一个会话:

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

就是这样。


我不同意你的结论,即connect-auth插件是要走的路。

我也在使用connect但我没有使用connect-auth有两个原因:

  1. IMHO打破了connect-auth非常强大且易于阅读的洋葱圈连接架构。禁止 - 我的意见:)。 你可以找到关于连接如何工作以及洋葱圈概念的非常好的简短文章here

  2. 如果你 - 正如所写 - 只想使用数据库或文件的基本或http登录。 Connect-auth太大了。它更适用于OAuth 1.0,OAuth 2.0等产品。共


  3. 使用connect

    进行非常简单的身份验证

    (它已经完成了。只需执行它进行测试,但如果你想在生产中使用它,请确保使用https) (要成为REST-Principle-Compliant,你应该使用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更改。如果我要更改任何内容,请添加评论。

答案 2 :(得分:26)

看起来连接中间件的connect-auth插件正是我需要的:http://wiki.github.com/ciaranj/connect-auth/creating-a-form-based-strategy

我正在使用express [http://expressjs.com]所以connect插件非常合适,因为express是从连接<(p)创建的子类(ok - prototyped)

答案 3 :(得分:14)

我基本上都在寻找相同的东西。具体来说,我想要以下内容:

  1. 使用包含Connect中间件功能的express.js
  2. “基于表单”身份验证
  3. 对哪些路由进行身份验证进行细化控制
  4. 用户/密码的数据库后端
  5. 使用会话
  6. 我最终做的是创建我自己的中间件函数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("/");
        }
      });
    });
    

    无论如何,这种方法主要是为了灵活和简单。我确信有很多方法可以改进它。如果你有,我非常希望得到你的反馈。

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

答案 4 :(得分:13)

如果您想要第三方/社交网络登录集成,请查看everyauth

答案 5 :(得分:7)

以下是我的一个项目的基本身份验证代码。我使用它和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;
    }

};

答案 6 :(得分:4)

对身份验证的另一种看法是无密码,一种用于表达的token-based authentication模块,可以避免密码的固有问题[1]。它实施起来快,不需要太多表单,并为普通用户提供更好的安全性(完全披露:我是作者)。

[1]:Passwords are Obsolete

答案 7 :(得分:3)

几年过去了,我想介绍一下Express的身份验证解决方案。它被称为 Lockit 。您可以在GitHub上找到该项目,在my blog找到简短的介绍。

那么现有解决方案有何不同?

  • 易于使用:设置数据库,安装npm,require('lockit')lockit(app),完成
  • 路由已经内置(/ signup,/ login,/忘记密码等)
  • 已经内置的视图(基于Bootstrap,但您可以轻松使用自己的视图)
  • 它支持AngularJS / Ember.js单页应用的JSON通信
  • 它不支持OAuth和OpenID。仅限usernamepassword
  • 它适用于几个开箱即用的数据库(CouchDB,MongoDB,SQL)
  • 它有测试(我找不到干墙的任何测试)
  • 积极维护(与everyauth相比)
  • 电子邮件验证和忘记密码处理(发送带有令牌的电子邮件,Passport不支持)
  • 模块化:仅使用您需要的内容
  • 灵活性:自定义所有内容

查看examples

答案 8 :(得分:2)

有一个名为Drywall的项目,它实现了一个Passport的用户登录系统,并且还有一个用户管理管理面板。如果您正在寻找一个功能齐全的用户身份验证和管理系统,类似于Django,但对于Node.js,就是这样。我发现它是构建需要用户身份验证和管理系统的节点应用程序的一个非常好的起点。有关Passport如何工作的信息,请参阅Jared Hanson's answer

答案 9 :(得分:2)

以下是两个用于节点js身份验证的流行Github库:

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

https://nodejsmodules.org/pkg/everyauth

答案 10 :(得分:1)

使用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);
}

答案 11 :(得分:0)

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

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

披露:我是这个图书馆的开发者。

答案 12 :(得分:0)

如果您需要使用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的作者。

答案 13 :(得分:0)

甜蜜身份验证

轻量级零配置用户身份验证模块。它不需要一个正确的数据库。

https://www.npmjs.com/package/sweet-auth

很简单:

        <div class="card">
                <div class="card-body"><div class="row">
            <div class="col-sm-1"></div>


            <div class="col-sm-7"></div>


            <div class="col-sm-4"></div>
            </div></div>
              </div>



In mobile width:

    Try like this    

        <div class="card">
                <div class="card-body"><div class="row">
            <div class="col-1"></div>


            <div class="col-7"></div>


            <div class="col-4"></div>
            </div></div>
              </div>

答案 14 :(得分:0)

有关手推方法的警告:

我很失望地看到本文中建议的一些代码示例并未防范诸如会话固定或定时攻击之类的基本身份验证漏洞。

与这里的一些建议相反,身份验证不是很简单,手动推销解决方案并不总是那么简单。我会推荐passportjsbcrypt

但是,如果您决定采用手动解决方案,请查看express js provided example以获得启发。

祝你好运。