2016-07-06 7 views
1

Ich arbeite derzeit an einer Autorisierungsfunktionalität für eine node.js Website. Ich arbeite mit Sequelize als ORM und Passport als Login-Manager. Um die Autorisierungsfunktionalität zu aktivieren, möchte ich dem Anforderungsobjekt (d. H. ["manageDelete", "manageAdd", "userManage"]) ein Autorisierungsname-Array (nur Zeichenfolgen) hinzufügen. Ich möchte das in der passport.deserializeUser() Methode tun. HierVerschachtelt fürEach und Asynchronität

ist einige zusätzliche Informationen:

Die Berechtigungen in einer MySQL-Datenbank-Tabelle gespeichert werden authorizations genannt. Diese Tabelle ist einer anderen Tabelle mit der Bezeichnung roles in einer n to m Beziehung zugeordnet (was ich letztendlich erreichen möchte, ist, die Berechtigungen zu bündeln, um die Verwaltung der Berechtigungen zu vereinfachen).

Ich habe große Probleme mit Async-Code, weil dieses Thema für mich sehr neu ist. Mein Code alle Berechtigungen der Rollen eines Benutzers zu sammeln, ist dies:

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

Ich weiß, dass wegen der asychronosity die done() Methode aufgerufen wird, bevor eine der Versprechungen gelöst werden, aber ich kann jede mögliche Weise nicht finden um das zu verhindern. Ich habe unzählige verschiedene Muster ausprobiert (z. B. https://www.joezimjs.com/javascript/patterns-asynchronous-programming-promises/ oder async.js), aber ich kann es nicht zum Laufen bringen.

Was mache ich falsch? Gibt es eine Lösung ohne zusätzliche Module? Hilfe würde sehr geschätzt werden. Danke im Voraus!

Antwort

0

Serialize verwendet drossel Versprechen und drossel hat eine .each Methode, die Sie bekommt, was man braucht. Ich denke, das ist viel prägnanter als die vorherige Lösung. Als eine Nebenbemerkung zeigt die Tatsache, dass Sie Pfeilfunktionen verwenden, an, dass Sie es6 verwenden. In diesem Fall bevorzuge ich const/let über var. Das Folgende sollte funktionieren, aber Sie könnten in der Lage sein, eine noch elegantere Lösung using bluebirds map/reduce-Methoden zu finden:

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

Vielen Dank! Ihre Lösung funktioniert einwandfrei! –

0

Das Problem in Ihrem Code ist, dass Sie kein Versprechen in Ihrem zweiten then() zurückgeben, so dass das leere authArr sofort zurückgegeben wird.

Was sollten Sie tun, ist:

  1. Return ein Versprechen in Ihrem zweiten then();
  2. Verwenden Sie etwas wie async, um sicherzustellen, dass alle Ihre role.getAuthorization() Anrufe abgeschlossen sind, bevor Sie das Versprechen lösen.

Hier ist, wie ich es tun würde.

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