我目前正在为node.js网站开发授权功能。我正在使用Sequelize作为ORM和Passport作为登录管理器。要启用授权功能,我想将一个授权名称数组(只是字符串)添加到请求对象(即["manageDelete", "manageAdd", "userManage"]
)。我想用passport.deserializeUser()
方法做到这一点。
以下是一些其他信息:
授权存储在名为authorizations
的MySQL数据库表中。此表与roles
关系中另一个名为n to m
的表相关联(我最终希望实现的是将授权捆绑在一起以便更轻松地管理授权)。
我对异步代码存在很大问题,因为这个主题对我来说很新。我的代码用于累积用户角色的所有授权:
passport.deserializeUser(function (id, done) {
var currUser;
models.User.findById(id)
.then((user) => {
currUser = user;
//gets array of associated roles for this user
return user.getRoles();
})
.then((roles) => {
var authArr = [];
roles.forEach((role) => {
//gets array of associated authorizations for this role
role.getAuthorizations().then((auths) => {
auths.forEach((auth) => {
authArr.push(auth.name);
});
});
});
return authArr;
})
.done((authArr) => {
done(null, {user: currUser, authArr: authArr});
});
});
我知道由于异步性,在解决任何promise之前调用了done()
方法,但我找不到任何方法来防止这种情况发生。我尝试了无数种不同的模式(例如:https://www.joezimjs.com/javascript/patterns-asynchronous-programming-promises/或async.js'),但我无法让它发挥作用。
我做错了什么?有没有使用任何额外模块的解决方案?帮助将非常感激。提前谢谢!
答案 0 :(得分:0)
您的代码中存在的问题是,您未在第二个then()
内返回承诺,因此会立即返回空的authArr
。
你应该做的是:
then()
; async
之类的内容确保所有role.getAuthorization()
来电完成。我会这样做。
passport.deserializeUser(function (id, done) {
var currUser;
models.User.findById(id)
.then((user) => {
currUser = user;
//gets array of associated roles for this user
return user.getRoles();
})
.then((roles) => {
return new Promise((resolve, reject) => { // Return a promise here. The next then() will wait for it to resolve before executing.
var authArr = [];
async.each(roles, (role, callback) => { // Use async.each to have the ability to call a callback when all iterations have been executed
//gets array of associated authorizations for this role
role.getAuthorizations().then((auths) => {
auths.forEach((auth) => {
authArr.push(auth.name);
});
callback(); // Tell async this iteration is complete.
});
}, (err) => { // Only called when all iterations have called callback()
if(err) reject(err);
resolve(authArr); // Resolve the promise so the next .then() is executed
});
});
})
.then((authArr) => {
done(null, {user: currUser, authArr: authArr});
});
});
答案 1 :(得分:0)
Serialize使用bluebird promises,bluebird有一个.each
方法可以满足你的需要。我认为这比以前的解决方案简洁得多。作为旁注,你使用箭头函数的事实表明你正在使用es6,在这种情况下我更喜欢const / let over var。以下应该可行,但您可以使用bluebird的map / reduce方法提出更优雅的解决方案:
passport.deserializeUser(function (id, done) {
let currUser;
const authArr = [];
return models.User.findById(id)
.then((user) => {
currUser = user;
//gets array of associated roles for this user
return User.getRoles();
})
.each((role) => {
//gets array of associated authorizations for this role
return role.getAuthorizations().each((auth) => {
authArr.push(auth.name);
});
})
.then(() => {
done(null, {user: currUser, authArr: authArr});
});
});