0

我必须遵循评估密码是否在用户密码历史记录中的功能。这是代码:

isPasswordInPwdHistory : function(redisClient, userId, encPassword, cb) {

        var key = 'user:' + userId + ':pwdhistory';
        redisClient.llen(key, function(err, reply) {
            if (err) {
                status.results = [ ];
                xutils.addStatusResultsItem(status.results, err, null, null, null);
                cb(status);
            }
            else {
                var numPwds = reply;

                var match = false;
                var funcError;

                for (i=0; i <= numPwds - 1; i++) {
                    var error;
                    var pwdValue;
                    redisClient.lindex(key, i, function(err, reply) {
                        if (err) {
                            console.log('lindex err = ' + err);
                            error = err;
                        }
                        else {
                            console.log('lindex reply = ' + reply);
                            console.log('lindex encPassword = ' + encPassword);
                            console.log('lindex (encPassword === reply) = ' + (encPassword === reply));
                            pwdValue = reply;
                        }
                    });

                    console.log('for-loop error = ' + error);
                    console.log('for-loop pwdValue = ' + pwdValue);
                    console.log('for-loop (encPassword === pwdValue) = ' + (encPassword === pwdValue));

                    if (error) {
                        funcError = error;
                        break;
                    }
                    else if (encPassword === pwdValue) {
                        console.log('passwords match');
                        match = true;
                        break;
                    }
                }

                console.log('funcError = ' + funcError);
                console.log('match = ' + match);

                if (funcError) {
                    status.results = [ ];
                    xutils.addStatusResultsItem(status.results, err, null, null, null);
                    cb(status);
                }
                else
                    cb(match);
            }
        });
    }

这是控制台输出:

for-loop error = undefined
for-loop pwdValue = undefined
for-loop (encPassword === pwdValue) = false
funcError = undefined
match = false
isPasswordInPwdHistory = false
lindex reply = 5f4f68ed57af9cb064217e7c28124d9b
lindex encPassword = 5f4f68ed57af9cb064217e7c28124d9b
lindex (encPassword === reply) = true

一旦我离开 redisClient.lindex() 调用的范围,我就会丢失这些值。如何在 for 循环中传递这些值以进行评估?

更新

当发出 redisClient.lindex() 回调时,我稍微重构了代码以处理新密码 (encPassword) 与索引 i 处现有密码的匹配。

isPasswordInPwdHistory : function(redisClient, userId, encPassword, cb) {

        var status = new Object();
        var key = 'user:' + userId + ':pwdhistory';

        redisClient.llen(key, function(err, reply) {
            if (err) {
                status.results = [ ];
                xutils.addStatusResultsItem(status.results, err, null, null, null);
                cb(status);
            }
            else {
                var numPwds = reply;
                var loopCt = 0;

                for (i=0; i <= numPwds - 1; i++) {
                    loopCt++;
                    redisClient.lindex(key, i, function(err, reply) {
                        if (err) {
                            status.results = [ ];
                            xutils.addStatusResultsItem(status.results, err, null, null, null);
                            cb(status);
                        }
                        else if (encPassword === reply) {
                            status.results = [ ];
                            xutils.addStatusResultsItem(status.results, null, 0, null, true);
                            cb(status);
                        }
                        else if (loopCt === numPwds && encPassword !== reply) {
                            status.results = [ ];
                            xutils.addStatusResultsItem(status.results, null, 0, null, false);
                            cb(status);
                        }
                    });
                }
            }
        });
    }

不幸的是,即使 encPassword === 回复为真并且我发出 cb(status),调用者仍看到状态 === 未定义。发出 cb(status) 后如何永久退出 for 循环?

4

1 回答 1

1

看起来您的逻辑中混合了同步和异步思维。您的for循环将尽可能快地触发对 Redis 的请求,而无需等待 Redis 响应(这是异步 IO 的本质)。因此,当您的代码运行时console.log('funcError = ' + funcError);console.log('match = ' + match);Redis 甚至可能还没有响应i循环中的第一个值(与您在输出中找到的值相匹配)。

我可能会研究像async这样的库来帮助完成这项任务;特别是,whilst看起来它可能很合适。也许是这样的:

var numPwds = reply;
...
var match = false;
var i = 0;

async.whilst(
  // keep looping until we have a match or we're done iterating the list
  function () { return match == false && i < numPwds; },

  // this is our function to actually check Redis
  function (callback) {
    redisClient.lindex(key, i, function(err, reply) {
      if (err) {
        console.log('lindex err = ' + err);
        error = err;
      }
      else {
        if (encPassword === reply) { match = true; } // this will cause `whilst` to stop.
      }
      i++;
      callback();
    });
  },

  function (err) {
    // this is called when our first function that calls
    // return match == false && i < numPwds
    // returns false, which will happen when we're out of list elements to check
    // or we have a match. At this point, match being true or false
    // let us know if we found the password.
  }
);

最后一点,除非您需要支持在“已使用密码”列表中多次显示相同的密码,否则您可以通过使用集合或排序集合来为自己省去很多麻烦。

于 2012-05-19T18:15:56.770 回答