2010-06-21 4 views
1

Pardon de la longueur ici ... je espère que je ne suis pas allé trop loin ...endroit approprié pour les évaluations de sécurité - la logique métier ou d'accès aux données

Je suis en train de travailler sur ma première production MVC application et j'essaie de s'en tenir aux principes DDD dans le processus. J'ai rencontré des questions sur la façon de traiter les exigences de sécurité de l'application et je pensais que la communauté SO pourrait offrir des suggestions de meilleures pratiques.

Informations sur le domaine

Pour utiliser une explication simplifiée, cette application aura AffiliateCompanies, Users et Customers.

  • AffiliateCompanies sont hierarchal, de sorte qu'un affilié peut s'inscrire et être lié aux activités d'un autre affilié. La racine est la principale entreprise fournissant les produits/services.
  • Users appartiennent tous à une entité affiliée.
  • Customers sont des organisations auxquelles les produits/services sont vendus. Les affiliés sont assignés aux clients de telle sorte qu'il est possible que deux affiliés hiérarchiquement indépendants divisent un client.

Informations sur la sécurité

Droits d'effectuer certaines actions dans l'application seront déterminées à partir d'une ACL type d'arrangement. Chaque objet User possède une propriété qui est une collection de SystemAccessRules qui détermine les actions qu'ils peuvent effectuer et la portée de leurs autorisations (leurs propres objets, les objets de leurs affiliés ou les objets de leur hiérarchie entière). Les utilisateurs peuvent également appartenir à des rôles qui possèdent eux-mêmes la même collection de SystemAccessRules. Par conséquent, si un utilisateur se connecte et souhaite voir une liste de «leurs» clients, la liste peut être composée de clients auxquels ils sont affectés individuellement, de clients auxquels leur organisation affiliée est affectée ou de clients. n'importe qui dans leur organisation ou l'une de leurs organisations d'enfants affiliées sont assignés à.

Considérations sur la base de données

DDD côté, à un moment donné la stratégie de stockage doit entrer en jeu. Dans ce scénario simple, les tables sont alignées avec les objets ci-dessus (y compris une table de rôles), avec quelques tables de soutien pour soutenir les relations entre les objets:

  • AffiliateCustomers - ce tableau permet un grand nombre à plusieurs relation entre les affiliés et les clients en stockant le PK de chaque entité comme une paire de FK qui sont eux-mêmes un PK composite pour cette table. - cette table stocke les informations de sécurité, en particulier l'objet de l'entrée (un utilisateur ou un rôle), l'action en question (par exemple "CreateCustomer"), la permission (autoriser ou refuser) et une portée (leurs propres affaires, celles de leur organisation ou de leur réseau).

La question ...Enfin

J'utilise une combinaison de référentiels et de services. J'essaie de garder la logique métier dans les services et hors des référentiels ou de la base de données, mais en raison de la conception de sécurité ici, une simple demande pour la liste de "leurs" clients pourrait être extrêmement lourde, surtout à mesure que l'ensemble de données augmente. J'essayais d'utiliser Linq quand c'était possible, mais cette architecture ne semble pas très adaptée. Comme je le vois, voici mes choix:

  1. Acceptez l'utilisateur qui demande comme argument pour les méthodes de service (ou le déterminer par le contexte), et ont la méthode de service remplir une liste par plusieurs requêtes au référentiel Linq. Cela nécessite d'extraire la liste des clients, puis de parcourir chaque client pour émettre une autre requête afin d'extraire les données ACL, puis d'utiliser ces données pour filtrer la première liste en fonction des autorisations. La question de la hiérarchie nécessiterait un jeu de jambes sophistiqué Linq (comme this), si c'est possible du tout.
    Même si la question de hiérarchie pourrait être au travail, il semble que cette solution ne sera pas très bien ... effectuer

  2. Accepter l'utilisateur demandeur comme un argument, mais le transmettre et l'autorisation nécessaire (par exemple "Voir les clients") pour récupérer les données appropriées de la base de données via une procédure stockée qui utiliserait plusieurs clauses EXISTS dans une requête CTE qui pourrait expliquer la nature hiérarchique des données et la nécessité de vérifier le rôle et la sécurité de l'utilisateur.
    Ceci pousse une bonne quantité de logique à la base de données, ce qui semble très anti-DDD et généralement mauvais.

Je suis plus vers la penchent deuxième option, mais peut-être parce que dans mes projets passés qui est comme ça que je l'ai fait. Je ne suis même pas sûr que mon design soit globalement sur la bonne voie (dans le passé, les déclarations d'autorisation étaient faites en utilisant des drapeaux bit, donc c'était encore plus facile de faire la requête DB en utilisant l'opérateur bitwise).

Est-ce que quelqu'un a été dans des situations similaires, et si oui pouvez-vous commenter sur la performance et la maintenabilité de la solution que vous avez suivie? Je veux m'en tenir à des principes de programmation ambitieux, mais pas au détriment de la simplicité et du bon sens.

+0

Juste un commentaire, pas une réponse, mais n'oubliez pas les principes KISS et YAGNI. Concevez votre code d'application autour des interfaces de référentiel/service afin que vous puissiez toujours changer ce qui est à l'intérieur de 1 à 2. Ensuite, faites l'implémentation la plus simple et la plus simple possible. Par exemple. 2 si c'est ce que vous avez l'habitude de faire. Ne mettez pas trop dans la conception, car quelque chose que vous avez manqué peut le casser plus tard. Essayez juste de le garder assez abstrait et de le refactoriser progressivement. – queen3

+0

Oui, je travaille à résister à l'envie de sur-ingénierie pour les exigences anticipées qui ne sont pas la réalité en ce moment. En même temps je ne veux pas me peindre dans un coin.Je pense que je vais devoir faire quelques tests pour voir à quel point il est difficile d'évaluer la sécurité en examinant le contenu d'une propriété 'IEnumerable ' sur chaque objet 'AffiliateCompany' de la liste. À la fin de la journée, c'est ce qui me motive à mettre cette évaluation dans la base de données ... Je sais que la base de données sera plus rapide, mais je ne sais pas à quelle vitesse. –

Répondre

0

Avez-vous envisagé d'utiliser le specification pattern pour transmettre vos règles métier à votre couche d'accès aux données?

Le service construit un arbre de spécifications qu'il transmet au référentiel. Le référentiel convertit la spécification en un Expression<Func<Customer, bool>> qu'il passe à IQueryable<Customer>.Where(...). Lorsque le référentiel matérialise la collection, par ex. En appelant ToList(), les règles métier sont traduites en SQL et exécutées sur le serveur de base de données.

La dernière fois que j'ai vérifié, LINQ to SQL ne supportait pas les CTE, vous devrez peut-être utiliser une vue pour aplatir la hiérarchie.

+0

En regardant ce modèle, j'aime que le code soit plus facile à lire. À l'heure actuelle, j'utilise une méthode d'extension Has (enum) pour tester si l'énumération de sécurité spécifiée fait partie du rôle de l'utilisateur, et ce n'est pas si grave. J'ai fini par aller aveC# 2, en envoyant l'information d'utilisateur et de rôle à la base de données et en la faisant filtrer les résultats. Cela fonctionne et fonctionne très bien, mais la maintenance s'avère un peu difficile car il est plus difficile de suivre les changements de DB. Une modification apportée à une table entraîne des modifications aux vues, fonctions, sprocs, etc. –

Questions connexes