2016-07-06 122 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}); 
    }); 
});