2016-07-06 84 views
1

我目前正在为node.js网站的授权功能。我正在使用Sequelize作为登录管理器的ORM和Passport。要启用授权功能,我想向请求对象(即["manageDelete", "manageAdd", "userManage"])添加授权名称数组(仅字符串)。我想在passport.deserializeUser()方法中这样做。嵌套for each和异步

下面是一些额外的信息:

的授权都存储在MySQL数据库中的表称为authorizations。此表与关联n to m关系的另一个名为roles的表关联(我最终想要实现的是将授权捆绑在一起以使管理授权更加容易)。

我有异步代码的巨大问题,因为这个话题对我来说是非常新的。我的代码来积累用户的角色的所有授权是这样的:

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

我知道,因为asychronosity的任何承诺都得到解决之前,done()方法被调用,但我找不到任何方式以防止发生。我尝试了无数不同的模式(例如:https://www.joezimjs.com/javascript/patterns-asynchronous-programming-promises/或async.js'),但我无法实现它。

我在做什么错?有没有使用任何额外的模块的解决方案?帮助将不胜感激。提前致谢!

回答

0

序列化使用蓝鸟承诺,蓝鸟有一个.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}); 
    }); 
}); 
+0

非常感谢!你的解决方案工作得很好! –

0

代码中的问题是您不会在第二个then()中返回承诺,因此将立即返回空的authArr

你应该做的是:

  1. 返回一个承诺你的第二个then();
  2. 使用类似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}); 
    }); 
});