Sommaire
L'autorisation dans CQRS / DDD doit-elle être implémentée par commande / requête ou non?
Je développe pour la première fois une application en ligne utilisant plus ou moins strictement le modèle DDD CQRS. J'ai rencontré un problème que je n'arrive pas vraiment à comprendre.
L'application que je construis est une application de grand livre permettant aux gens de créer des grands livres, ainsi qu'à d'autres personnes de les afficher / modifier / supprimer, comme les employés. Le créateur d'un livre doit pouvoir modifier les droits d'accès du livre qu'il a créé. Pourrait même changer de propriétaire. Le domaine a deux agrégats TLedger et TUser .
J'ai lu beaucoup de messages avec le mot-clé DDD / CQRS concernant la sécurité, l'autorisation, etc. La plupart d'entre eux ont déclaré que l'autorisation était un sous- domaine générique , à moins que l'on ne crée une application de sécurité.
Dans ce cas, le domaine principal est certainement un domaine comptable intéressé par les transactions, l'équilibre et les comptes. Mais la fonctionnalité de pouvoir gérer un accès fin aux registres est également requise. Je me demande comment concevoir cela en termes DDD / CQRS.
Il est indiqué dans les didacticiels DDD partout dans le monde que les commandes font partie du langage omniprésent. Ils sont significatifs. Ce sont des actions concrètes qui représentent la «vraie chose».
Étant donné que toutes ces commandes et requêtes sont des actions réelles que les utilisateurs exécuteraient dans la «vie réelle», la mise en œuvre de l'autorisation devrait-elle être associée à toutes ces «commandes» et «requêtes»? Un utilisateur serait autorisé à exécuter TLedger.addTransaction () mais pas TLedger.removeTransaction () par exemple. Ou, un utilisateur serait autorisé à exécuter la requête "getSummaries ()" mais pas "getTransactions ()".
Un mappage tridimensionnel existerait sous la forme d'une commande de registre utilisateur ou d'une requête de registre utilisateur pour déterminer les droits d'accès.
Ou, de manière découplée, des «autorisations» nommées seraient enregistrées pour un utilisateur. Autorisations qui seraient ensuite mappées pour des commandes spécifiques. Par exemple, l'autorisation "ManageTransactions" permettrait à un utilisateur d'exécuter "AddTransaction ()", "RemoveTransaction ()", etc.
Utilisateur de mappage des autorisations -> ledger -> commande / requête
Utilisateur de mappage des autorisations -> registre -> autorisation -> commande / requête
C'est la première partie de la question. Ou en bref, l'autorisation dans CQRS / DDD doit-elle être implémentée par commande ou par requête? Ou, l'autorisation doit-elle être découplée des commandes?
Deuxièmement, concernant l'autorisation basée sur les autorisations. Un utilisateur doit être en mesure de gérer les autorisations sur ses livres ou sur les livres qu'il a été autorisé à gérer.
- Les commandes de gestion des autorisations se produisent dans le Ledger
J'ai pensé ajouter les événements / commandes / gestionnaires dans l' agrégat Ledger , tels que grantPermission (), revokePermission (), etc. Dans ce cas, l'application de ces règles se produirait dans les gestionnaires de commandes. Mais cela nécessiterait que toutes les commandes incluent l'ID de l'utilisateur qui a émis cette commande. Ensuite, je vérifierais dans le TLedger si l'autorisation existe pour cet utilisateur d'exécuter cette commande.
Par exemple :
class TLedger{
function addTransactionCmdHandler(cmd){
if (!this.permissions.exist(user, 'addTransaction')
throw new Error('Not Authorized');
}
}
- Commandes de gestion des autorisations dans l'utilisateur
L'autre solution consisterait à inclure les autorisations dans le TUser. Un TUser aurait un ensemble d'autorisations. Ensuite, dans les gestionnaires de commandes TLedger, je récupérais l'utilisateur et vérifiais s'il était autorisé à exécuter la commande. Mais cela m'obligerait à récupérer l'agrégat TUser pour chaque commande TLedger.
class TAddTransactionCmdHandler(cmd) {
this.userRepository.find(cmd.userId)
.then(function(user){
if (!user.can(cmd)){
throw new Error('Not authorized');
}
return this.ledgerRepository.find(cmd.ledgerId);
})
.then(function(ledger){
ledger.addTransaction(cmd);
})
}
- Un autre domaine avec service
Une autre possibilité serait de modéliser complètement un autre domaine d'autorisation. Ce domaine serait intéressé par les droits d'accès, l'autorisation etc. Le sous-domaine comptable utiliserait alors un service pour accéder à ce domaine d'autorisation sous la forme de AuthorizationService.isAuthorized(user, command)
.
class TAddTransactionCmdHandler(cmd) {
authService.isAuthorized(cmd)
.then(function(authorized){
if (!authorized) throw new Error('Not authorized');
return this.ledgerRepository.find(cmd.ledgerId)
})
.then(function(){
ledger.addTransaction(cmd);
})
}
Quelle serait la décision la plus "DDD / CQRS"?