我试图使用一系列承诺来验证用户名和密码,但看到的承诺过早解决。
我在这里涉及两个不同文件的两个方法。
首先,我的控制器,它接收请求并调用我的模型进行身份验证。该模型应该返回一个在结算时将具有身份验证结果的承诺。
这是我的控制器:
router.post('/api/auth-tokens', function (req, res, next) {
var creds = {user: req.body.user, password: req.body.password};
people.authenticate(creds)
.then(function (result) {
var status = result.valid ? 200: 401;
res.sendStatus(status);
});
});
people
是词法范围的模型。以下是上述方法的当前实现:
var bluebird = require('bluebird');
var bcrypt = require('bcrypt');
var compare = bluebird.promisify(bcrypt.compare);
exports.authenticate = function (args) {
var promise = orm.select({
db: db,
table: table,
where: {id: args.user},
qrm: 'one'
});
promise.catch(function (err) {
var auth_info = { valid: false };
return auth_info;
});
promise.then(function (user) {
var promise = compare(args.password, user.hash)
.then(function (same) {
var auth_info = { valid: same, permissions: user.permissions };
return auth_info;
});
return promise;
});
return promise;
};
orm
返回一个承诺,如果用户不存在则会抛出错误,或者如果找到用户则解析并生成数据库行。 (这就是我在那里进行promise.catch
调用的原因。以防用户不存在)
如果用户确实存在,我想调用bcrypt.compare
来比较数据库行中包含的哈希的输入。当异步完成时,我想解析promise链并将控制权返回给控制器,返回results
对象。
我遇到的问题是我的控制器中的.then
正在立即执行,而orm.select
的调用返回了初始承诺的结果。任何人都可以解释为什么会发生这种情况以及如何解决它?
答案 0 :(得分:2)
这种情况正在发生,因为您已将该回调直接连接到orm.select
返回的承诺。相反,您需要使用then
返回的承诺。
这是关于承诺的最重要的关键事项之一: then
返回新承诺。 (catch
也是如此。)如果你的处理函数从then
或catch
返回一个promise(技术上,任何 thenable ),那么then
的新承诺1}}(或catch
)返回将根据您返回的承诺解析/拒绝。如果您的处理函数返回非承诺值,则then
(或catch
)的新承诺将使用该值解析(不被拒绝)。
所以authenticate
应该是这样的:
exports.authenticate = function (args) {
return orm.select({
db: db,
table: table,
where: {id: args.user},
qrm: 'one'
})
.then(function (user) {
return compare(args.password, user.hash)
.then(function (same) {
var auth_info = { valid: same, permissions: user.permissions };
return auth_info;
});
})
.catch(function (err) {
var auth_info = { valid: false };
return auth_info;
});
};
请注意,更改既适用于您的外部功能,也适用于您在then
中执行的操作。另请注意,catch
回调中的代码将被调用,无论是来自orm.select
的被拒绝的原始承诺,还是来自compare
的承诺。
要查看正在发生的事情,请将此代码段与之后的代码段进行比较:
// Returning the original promise
// Usually NOT what you want
function foo() {
var promise = new Promise(function(resolve) {
console.log("Starting first promise");
setTimeout(function() {
console.log("Resolving first promise");
resolve("first");
}, 500);
});
promise.then(function() {
promise = new Promise(function(resolve) {
console.log("Starting second promise");
setTimeout(function() {
console.log("Resolving second promise");
resolve("second");
}, 500);
});
});
return promise;
}
foo().then(function(result) {
console.log("Got result: " + result);
});
第二
// Returning the original promise
// Usually NOT what you want
function foo() {
return new Promise(function(resolve) {
console.log("Starting first promise");
setTimeout(function() {
console.log("Resolving first promise");
resolve("first");
}, 500);
})
.then(function() {
return new Promise(function(resolve) {
console.log("Starting second promise");
setTimeout(function() {
console.log("Resolving second promise");
resolve("second");
}, 500);
});
});
}
foo().then(function(result) {
console.log("Got result: " + result);
});
答案 1 :(得分:1)
您的控制器正在执行与使用bcrypt.compare
的承诺不同的承诺这样做是为了确保people.authenticate返回一个声明链,该声明链解析为比较后的内部结果:
var promise = orm.select(/* ... */)
.then(/* bcrypt usage here */)
.catch(/* error handling here */);
return promise;