web-dev-qa-db-fra.com

Implémentation de DDD: utilisateurs et autorisations

Je travaille sur une petite application essayant de comprendre les principes de la conception pilotée par domaine. En cas de succès, cela pourrait être un pilote pour un projet plus vaste. J'essaie de suivre le livre "Implémentation de la conception pilotée par le domaine" (par Vaughn Vernon) et j'essaie d'implémenter un forum de discussion simple et similaire. J'ai également vérifié les échantillons IDDD sur github. J'ai quelques difficultés à adopter l'identité et l'accès à mon dossier. Permettez-moi de donner quelques informations générales:

  • J'espère (je l'espère) comprendre le raisonnement derrière la séparation de la logique des utilisateurs et des autorisations: c'est un domaine de prise en charge et c'est un contexte borné différent.
  • Dans le domaine principal, il n'y a pas d'utilisateurs, juste des auteurs, des modérateurs, etc. Ceux-ci sont créés en atteignant le contexte d'identité et d'accès à l'aide d'un service, puis en traduisant les objets utilisateur reçus vers et le modérateur.
  • Les opérations de domaine sont appelées avec un rôle associé comme paramètre: par exemple:

    ModeratePost( ..., moderator);

  • La méthode de l'objet domaine vérifie si l'instance Moderator donnée n'est pas nulle (l'instance Moderator sera nulle si l'utilisateur demandé dans le contexte Identity and Access n'a pas le rôle Moderator).

  • Dans un cas, il effectue une vérification supplémentaire avant de modifier une publication:

    if (forum.IsModeratedby(moderator))

Mes questions sont:

  • Dans ce dernier cas, les problèmes de sécurité ne sont-ils pas à nouveau intégrés au domaine principal? Auparavant, les livres stipulaient "avec qui peut publier un sujet, ou dans quelles conditions cela est autorisé. Un forum a juste besoin de savoir qu'un auteur le fait en ce moment".

  • L'implémentation basée sur les rôles dans le livre est assez simple: lorsqu'un modérateur est le domaine principal essaie de convertir l'ID utilisateur actuel en une instance de modérateur ou en un auteur lorsqu'il en a besoin. Le service répondra avec l'instance appropriée ou une valeur nulle si l'utilisateur n'a pas le rôle requis. Cependant, je ne vois pas comment l'adapter à un modèle de sécurité plus complexe; notre projet actuel pour lequel je pilote a un modèle assez complexe avec des groupes, des ACL, etc.

Même avec des règles qui ne sont pas très complexes, comme: "Un article ne doit être édité que par son propriétaire ou un éditeur", cette approche semble s'effondrer, ou du moins je ne vois pas la bonne façon de l'implémenter.

En demandant le contexte d'identité et d'accès pour une instance OwnerOrEditor ne me semble pas correct, et je me retrouverais avec de plus en plus de classes liées à la sécurité dans le domaine principal. De plus, je devrais passer non seulement l'ID utilisateur, mais l'identifiant de la ressource protégée (l'id de la publication, du forum, etc.) au contexte de sécurité, qui ne devrait probablement pas se soucier de ces choses (est-ce correct? )

En tirant les autorisations sur le domaine principal et en les vérifiant dans les méthodes des objets de domaine ou dans les services, je me retrouvais à la case départ: mélanger les problèmes de sécurité avec le domaine.

J'ai lu quelque part (et j'ai tendance à être d'accord avec lui) que ces choses liées aux autorisations ne devraient pas faire partie du domaine principal, à moins que la sécurité et les autorisations ne soient le domaine principal lui-même. Une règle simple comme celle donnée ci-dessus justifie-t-elle de faire de la sécurité une partie du domaine principal?

18
LittlePilgrim

Il est parfois difficile de faire la distinction entre les règles de contrôle d'accès réelles et les invariants de domaine limitant le contrôle d'accès.

En particulier, les règles qui dépendent de données disponibles uniquement très loin dans le cours d'un morceau particulier de logique de domaine peuvent ne pas être facilement extractibles hors du domaine. Habituellement, le contrôle d'accès est appelé avant ou après une opération de domaine, mais pas pendant.

L'exemple assert (forum.IsModeratedBy(moderator)) de Vaughn Vernon aurait probablement dû être en dehors du domaine, mais ce n'est pas toujours faisable.

Il faudrait que je passe non seulement l'ID utilisateur, mais l'identifiant de la ressource protégée (l'identifiant de la publication, le forum, etc.) au contexte de sécurité, qui ne devrait probablement pas se soucier de ces choses (est-ce correct?)

S'il y a un Security BC et que vous voulez qu'il gère cette logique, il n'a pas besoin de savoir ce qu'est un Forum en détail mais:

  • Il pourrait simplement avoir des connaissances sur des concepts tels que "modéré par" et accorder ou refuser des droits d'accès en conséquence.
  • Vous pouvez avoir une logique d'adaptateur qui s'abonne aux événements du domaine principal et les traduit en paires de valeurs de clé simples (ressource, utilisateurs autorisés) que Security BC doit stocker et utiliser.
7
guillaume31

L'authentification et l'autorisation sont un mauvais exemple pour DDD.

Aucune de ces choses ne fait partie d'un domaine à moins que votre entreprise ne crée des produits de sécurité.

L'exigence d'entreprise ou de domaine est ou devrait être "J'exige une authentification basée sur les rôles"

Vous vérifiez ensuite le rôle avant d'appeler une fonction de domaine.

Lorsque vous avez des exigences complexes telles que "Je peux modifier mes propres publications mais pas les autres", assurez-vous que votre domaine sépare la fonction de modification en EditOwnPost() et EditOthersPost() afin d'avoir une fonction simple à la cartographie des rôles

Vous pouvez également séparer la fonctionnalité en objets de domaine, tels que Poster.EditPost() et Moderator.EditPost() c'est une approche plus OOP, bien que votre choix puisse dépendre de votre méthode se trouve dans un service de domaine ou un objet de domaine.

Quelle que soit la manière dont vous choisissez de séparer le code, le mappage de rôle se produira en dehors du domaine. ainsi par exemple si vous avez un contrôleur webapi:

PostController : ApiController
{
    [Authorize(Roles = "User")]
    public void EditOwnPost(string postId, string newContent)
    {
        this.postDomainService.EditOwnPost(postId, string newContent);
    }

    [Authorize(Roles = "Moderator")]
    public void EditOtherPost(string postId, string newContent)
    {
        this.postDomainService.EditOtherPost(postId, string newContent);
    }
}

Comme vous pouvez le constater, bien que le mappage des rôles soit effectué sur la couche d'hébergement, la logique complexe de ce qui constitue la modification de votre propre ou d'un autres post fait partie du domaine.

Le domaine reconnaît la différence des actions, mais l'exigence de sécurité est simplement que "la fonctionnalité peut être limitée par les rôles".

C'est peut-être plus clair avec la séparation des objets de domaine, mais vous vérifiez essentiellement la méthode qui construit l'objet au lieu de la méthode qui appelle la méthode de service. Votre exigence, si vous voulez toujours l'exprimer dans le cadre du domaine deviendrait 'seuls les modérateurs peuvent construire l'objet modérateur'

5
Ewan

J'ai rencontré le même questionnement et je poste la réponse que j'ai trouvée car cela pourrait donner une vision supplémentaire sur le sujet, même si la discussion a eu lieu il y a quelque temps (toujours le deuxième lien sur le sujet dans Google).

Je pense qu'il y a deux types différents de contrôles d'accès en jeu:

  • Validation des rôles en termes de schéma d'authentification
  • Validation des actions en termes commerciaux

Savoir si un utilisateur particulier est un modérateur appartient au contexte délimité Identité & Accès. C'est parce que cela a à voir avec les droits de l'utilisateur - sa catégorie.

Mais

Savoir si un modérateur peut éditer une publication appartient au domaine professionnel et doit être hors du contexte délimité Identité & Accès. Une bonne façon de voir cela est que la condition est exprimée sans se référer à l'utilisateur ciblé: c'est une règle commerciale qu'un modérateur peut ou ne peut pas éditer la publication d'un autre modérateur par exemple. Il ne doit pas polluer Identity & Access BC.

Il devient particulièrement clair lorsque vous souhaitez appliquer ce raisonnement à étendues dans un paramètre OAuth. Maintenant, en plus des règles d'authentification, vous devez également autoriser des actions selon que des portées spécifiques sont incluses ou non dans la demande de jeton. Où mettez-vous cela?

Je dirais que vous mettez cela dans l'entreprise BC. En effet, la sémantique des étendues est connue du domaine métier. Avoir un rôle spécifique et savoir ce qu'il permet de faire sont deux choses différentes. La première partie est dans le I&A BC, la deuxième partie est dans le domaine des affaires.

Et cela semble juste: si soudain vous voulez interdire l'édition d'un sujet par un modérateur, vous devriez avoir à modifier le forum BC, pas le I&A BC - rien n'a vraiment changé pour la définition des rôles, c'est juste leur sémantique dans un BC spécifique qui a changé.

C'est pourquoi je pense que c'est la meilleure solution pour avoir la vérification if (forum.IsModeratedby(moderator)) dans l'entreprise BC. Je suppose que je ne suis pas d'accord avec la réponse acceptée à ce sujet.

Si de nombreuses règles comme celle-ci existent pour une entreprise en particulier en Colombie-Britannique, il me semble que la meilleure façon est de les regrouper dans un sous-domaine de l'entreprise en Colombie-Britannique. De telles règles métier peuvent bénéficier de leur incarnation en tant qu'objet à appeler (comme un modèle de stratégie ).

1
Qortex