【问题标题】:Node basic auth with loading credentials from Database从数据库加载凭据的节点基本身份验证
【发布时间】:2018-05-14 21:38:49
【问题描述】:

我在服务器上使用 NodeJs,我需要添加一些基本的身份验证功能,该功能在将任何文件(如 html 或 js 文件)下载到用户的浏览器之前要求用户提供凭据。当我在未登录时尝试查看源代码时,我无法像在this 中那样访问它。 这适用于 basic-auth 模块,但仅适用于一个用户名和密码。

app.use(basicAuth('username', 'password'));

还有一个问题——我需要从数据库中加载这个凭据并检查用户是否是管理员并比较他的加密密码。 我试过这个:

// ****
var basicAuth = require('basic-auth');
// ****
app.use(function (req, res, next) {

  var user = basicAuth(req);
  if (user) {
      var c = mysql.createConnection(db);
      var q = "SELECT * FROM user WHERE email = '" + user.name + "' AND admin = 1;";
      c.query(q, function (error, result) {
          c.end();
          if (error) {
              console.log(error);
              res.set('WWW-Authenticate', 'Basic realm="example"');
              return res.status(401).send();
          } else {
              if (result.length === 1 &&
                  bcrypt.compareSync(user.pass, result[0].password)) {

                  return next();
              } else {
                  res.set('WWW-Authenticate', 'Basic realm="example"');
                  return res.status(401).send();
              }
          }
      });
  } else {
      res.set('WWW-Authenticate', 'Basic realm="example"');
      return res.status(401).send();
  }
});

这很好用,但是每次浏览器与服务器通信时都会调用此函数,加载简单页面时大约是 70 次(它不会再次询问用户凭据,“仅”运行此函数)。这个函数每次请求持续约200ms(因为查询和密码比较),总之加载持续约15秒,这是不可接受的。

你能帮我解决这个问题吗?或者向我推荐一些其他的 NodeJs 库,可以帮助我解决这个问题吗?

谢谢。

【问题讨论】:

    标签: javascript node.js authentication basic-authentication


    【解决方案1】:

    因此,如果您将哈希存储在数据库中,并将管理标志存储在数据库中,为什么不执行以下选择请求:

    var q = "SELECT * FROM user WHERE email = '" + user.name + "' AND password = '" + bcrypt.hashSync(user.pass) + "' AND admin = '1';";
    

    如果只得到一个结果就OK,否则就被拒绝...

    【讨论】:

    • 这并不容易,您必须仅使用bcrypt.compareSync(user.pass, hash) 将密码与哈希值进行比较,您的方法不起作用。然而这并不能解决问题,因为这不会在加载时加快页面速度......
    • 嗯...如果您减少 200 毫秒可能会有所帮助。但我忘记了盐,同意。
    【解决方案2】:

    如果我理解您的问题,对服务器的每个请求都在运行您的身份验证,导致页面加载缓慢。我不明白如果所有路由都在您正在执行的基本身份验证检查之后,那么有人如何登录,但这不是重点。

    我设置节点应用程序的方式是为身份验证创建一组函数,并将这些函数传递给我需要身份验证的特定路由,这样它就可以为我可能服务的每个资源运行。例如(伪代码):

    // this is the authentication function array, each function in the array
    // will be run when this array is called on a route, require next()
    // after successful auth to continue on through the array/route handlers
    
    // for your example, adminAuth would be the anonymous 
    // function in your app.use method
    var auth = [adminAuth];
    
    // some random route examples
    
    // this is an unprotected route
    app.get('/login', loginHandler);
    
    // these are protected routes and will have auth called
    app.get('/api/users', auth, getUserHandler);
    app.post('/api/user', auth, postUserHandler);
    

    因此,总而言之,您可以只对受保护的资源进行身份验证调用,这样就可以提供图像、html、js、css 等,而无需每次都运行身份验证检查。

    【讨论】:

      【解决方案3】:

      您的代码存在一些问题。我认识到您需要对每个请求进行密码检查,但您不一定需要每次都访问数据库。假设您必须使用 HTTP Basic(不再推荐,我希望如果您是,那么您是通过 HTTPS 进行的),那么您可以做出的一项重大改进是,如果您创建某种快速数据缓存。最简单的形式是内存中(假设您对应用程序的每个实例都保留自己的副本感到满意),但您也可以根据您的用例使用 memcached 或 redis 之类的东西。

      一个非常简单的实现就是保留一个内存中的 JS 对象,其键等于用户名,值等于从数据库返回的数据。比如:

      var userCache = {}; // something local to the module is the easiest way
      

      然后,当您要查询数据库时,您只需先检查userCache

      if(userCache[user.name]) // check password
      else
       // do your query and insert a successful result into the userCache for later. 
      

      这样做应该会显着减少每个资源的响应时间,但对于生产解决方案,您可能需要多层缓存(例如,内存缓存和 redis 或 memcached 缓存,以帮助跨多个实例的性能)你的应用程序)。

      其次,您应该使用 bcrypt 检查的回调版本。对于给定的请求,它不会更快,但它可能会为您的应用程序提供更多的整体请求容量,这应该会有所帮助。

      第三,由于三个原因,您的实际 SQL 查询是一个坏主意。首先,在大多数数据库中,使用SELECT * 与选择所需的特定字段相比,性能会更差。这既在 DB 端(查询缓存优化)也在 Node 端(处理字段在字符串响应和 JS 对象之间转换/转换的时间)。其次,您正在执行的字符串连接是对SQL Injection attacks 的邀请。考虑改用参数化查询。最后,如果您知道您的用户将是独一无二的,您还应该在查询中添加LIMIT 1,因为您只期待一个结果,并且数据库可以再次对此进行一些优化。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-03-19
        • 2011-11-12
        • 2017-11-11
        • 2020-02-24
        • 1970-01-01
        • 2015-07-26
        • 2012-08-30
        • 2020-12-03
        相关资源
        最近更新 更多