2016-07-06 5 views
1

В настоящее время я работаю над полномочиями авторизации для узла node.js. Я работаю с Sequelize как ORM и Passport в качестве менеджера входа в систему. Чтобы включить функцию авторизации, я хочу добавить массив имен авторизации (только строки) в объект запроса (т. Е. ["manageDelete", "manageAdd", "userManage"]). Я хочу сделать это в методе passport.deserializeUser().Вложенный forEach и асинхронность

Вот некоторая дополнительная информация:

уполномочена хранятся в таблице базы данных MySQL называется authorizations. Эта таблица связана с другой таблицей 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}); 
    }); 
}); 

Я знаю, что из-за asychronosity метод done() вызывается перед любыми из этих обещаний будут решены, но я не могу найти способ чтобы это не происходило. Я пробовал бесчисленные разные шаблоны (например, это: https://www.joezimjs.com/javascript/patterns-asynchronous-programming-promises/ или async.js '), но я не могу заставить его работать.

Что я делаю неправильно? Есть ли какое-либо решение без использования каких-либо дополнительных модулей? Помощь будет оценена очень много. Заранее спасибо!

ответ

0

Serialize использует Bluebird обещания, и Блюберд имеет .each метод, который получает вас, что вам нужно. Я думаю, что это гораздо более кратким, чем предыдущее решение. В качестве примечания, тот факт, что вы используете функции стрелок, указывает, что вы используете es6, и в этом случае я предпочитаю const/let over var. Следующее должно работать, но вы можете придумать еще более изящное решение, использующее карты/методы сокращения bluebird:

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}); 
    }); 
}); 
Смежные вопросы