2009-10-10 7 views
25

Je suis à la recherche d'informations sur la façon dont les autres architectureraient cela. Je vais fournir des vues basées sur la classe (groupe django). Par exemple, le groupe d'un utilisateur déterminera les vues/modèles auxquels il aura accès. Je pense à peut-être stocker des chemins pour voir les fonctions dans une table pour déterminer ce que la barre de liens d'un utilisateur sera constitué. Les spécifications de filtre peuvent également être stockées pour déterminer quelles lignes rempliront ces modèles.Vues basées sur le rôle Django?

Un bon exemple est une unité de soins hospitaliers. Les infirmières d'une unité n'ont pas besoin de voir tous les patients de l'hôpital. Ils ont seulement besoin de voir leurs patients. Les médecins de la même unité doivent seulement voir ces patients, mais ils devraient avoir accès à une fonctionnalité beaucoup plus grande.

Est-ce que cela a été fait via une application tierce? Et comment aborderiez-vous ce problème?

Merci, Pete

+1

Les gars, le système d'autorisation de django ne correspond pas à mes besoins. C'est pourquoi je demande de l'aide pour l'architecture: P – slypete

Répondre

38

Django a déjà un système de groupes et les autorisations, ce qui peut être suffisant pour vos besoins.

http://docs.djangoproject.com/en/dev/topics/auth/

En général, dans votre code, vous vérifier si un utilisateur a une autorisation. Un utilisateur a ses propres permissions et celles des groupes auxquels il appartient. Vous pouvez l'administrer facilement depuis la console d'administration.

Vous devez examiner deux parties.

  1. Vérifiez qu'un utilisateur demandant une page a l'autorisation de le faire.
  2. Afficher uniquement les liens vers l'utilisateur s'il a la permission .

Pour 1. Vous pouvez vérifier les autorisations dans un décorateur en tant que tel:

from django.contrib.auth.decorators import permission_required 

@permission_required('polls.can_vote') 
def some_view(request): 

Pour 2. sont stockées les autorisations de l'utilisateur connecté actuellement à la variable de modèle {{perms}}. Ce code vérifie la même autorisation que ci-dessus.

{% if perms.polls.can_vote %} 
    <a href="/vote">vote</a> 
{% endif %} 

Pour générer une liste de liens que vous pouvez parcourir user.get_all_permissions() et récupérer les liens (ou une fonction qui génère le lien) à partir d'un dict:

def more_elaborate_list_of_links_for_a_perm(user): 
    return ["/link1", ...] 

_LINKS = { 
    'polls.can_vote' : lambda u: ["/user/specific/link/" + u.id], 
    'polls.can_close': lambda u: ['/static/link/1', 'static/link/2'], 
    'polls.can_open' : more_elaborate_list_of_links_for_a_perm 
} 

def gen_links(user): 
    # get_all_permissions also gets permissions for users groups 
    perms = user.get_all_permissions() 
    return sum((_LINKS[p](user) for p in perms if p in _LINKS), []) 

Il y a probablement beaucoup d'autres approches.

+1

Comment générer une liste de liens pour fournir un utilisateur utilisant le système d'autorisations intégré de django? – slypete

+1

Pour la petite histoire, je n'ai pas choisi cette réponse comme étant la meilleure. Je ne le pense pas. – slypete

1

Si vous n'avez pas besoin d'ACL réelle par objet, vous pouvez simplement utiliser le système d'autorisation Django. Pour obtenir une liste de toutes les autorisations disponibles:

from django.contrib.auth.models import Permission 
perms = Permission.objects.all() 

Il y a un API for other authentication and authorization sources, de sorte que vous n'avez pas besoin de rester avec cette table d'autorisations.

Vous pouvez pirater ce système Django pour répondre à vos besoins en termes de ce modèle d'autorisation (RBAC) ou vous pouvez créer une solution de type ACL.

+0

un indice pour un acl par objet? – gpilotino

4

Nous avons eu un problème similaire. Les groupes de Django ne sont pas vraiment adaptés à cela, mais vous pouvez les utiliser.

La façon dont nous l'avons fait était la suivante:

Chaque objet accès contrôlé a une relation de ManyToMany à la table des groupes. Chaque groupe a été utilisé pour définir un type spécifique de permission ("peut voir les bases du patient", "peut éditer les informations de contact du patient", et ainsi de suite). Les utilisateurs sont ajoutés aux groupes pour lesquels ils devraient avoir des autorisations (dans votre exemple de voir uniquement les patients dans cet hôpital, vous pourriez avoir un groupe "vallée-vue-hôpital").

Ensuite, lorsque vous allez afficher une liste d'enregistrements à un utilisateur, vous filtrez en fonction de la conjonction des deux groupes. Un utilisateur doit posséder toutes les autorisations de groupe associées pour afficher un objet donné.

Si votre système l'exige, vous pouvez conserver un ManyToMany distinct d'autorisations négatives, ou des autorisations de lecture/écriture séparées. Vous pouvez également définir un ensemble de méta-groupes (médecin, infirmière) qui aboutissent à votre filtre de recherche récupérant le sous-ensemble réel des autorisations. Dans la mesure où votre problème de barre de liaison disparaît, vous pouvez générer ceux utilisant le même système - filtre basé sur les classes d'objets que l'utilisateur peut voir ou modifier, puis utiliser une fonction de type get_absolute_url() (peut-être get_index_url()) pour renvoyer les liens pour l'index de chaque classe d'objet. Parce que tout cela est assez complexe, vous aurez probablement envie de faire un certain niveau de mise en cache pour ces choses, mais le faire fonctionner avant de vous embêter à l'optimisation. C'est possible, et c'est moins moche dans le code que dans les mots.

+0

J'ai fini par suivre cette route avec notre application, mais ce n'est pas idéal. J'ai trouvé la performance a chuté un peu. Je cherche ailleurs une meilleure solution ACL – Gevious

+0

Ce n'est pas évolutif du tout. Des idées sur ACL? – user710907

2

J'ai eu un problème similaire il n'y a pas si longtemps. Notre solution a fait l'affaire, même si cela pourrait être trop simple pour votre situation. Comme tout le monde le suggère, nous avons utilisé le système d'autorisation django pour contrôler les interactions de l'utilisateur avec les modèles. Cependant, nous n'avons pas seulement essayé de grouper les utilisateurs, nous avons également regroupé les objets via une GenericForeignKey.

Nous avons construit un modèle lié à lui-même pour permettre le développement de hiérarchies. Pour le faire fonctionner, nous avons également créé un modèle qui servira de profil d'utilisateur pour le modèle d'utilisateur django. Tout ce qu'il contenait était un ManyToManyField lié au modèle du groupe ci-dessus. Cela nous a permis de donner aux utilisateurs l'accès à zéro ou plusieurs groupes, au besoin. (documentation)

class UserProfile(models.Model): 
    user = models.ForeignKey(User, unique=True) 
    groups = models.ManyToManyField(Group) 
    ... 

Cela nous a donné le meilleur des deux mondes et nous a empêché d'essayer de caser tout dans le système d'autorisation de django. J'utilise cette configuration de base pour contrôler l'accès des utilisateurs au contenu sportif (certains utilisateurs peuvent accéder à des ligues entières, certaines seulement une ou deux conférences, d'autres n'ont accès qu'à des équipes individuelles), et cela fonctionne bien dans cette situation. Il pourrait probablement être assez généralisé pour répondre à vos besoins.

1

Sur un site pour un expert sur le vin Pinot Noir, nous avons créé un accès par objet basé sur un certain nombre de critères différents. Si le lien entrant contenait un champ référent correspondant au nom de domaine d'un établissement vinicole sélectionné, l'utilisateur recevait un «jeton de cave» qui s'étendait à tous les articles, notes de dégustation, etc. liés à cette cave. Nous utilisons des «jetons nommés» pour donner à des événements de dégustation et ils ont donné accès à des parties spécifiques du site. Nous utilisons même cela pour accorder certains types d'autorisations aux moteurs de recherche, puis nous assurer que les liens qui proviennent de ces moteurs de recherche ont les mêmes autorisations que l'araignée (c'est-à-dire pas de jeux de dissimulation).La version courte est que vous pouvez créer une classe (nous les avons appelés TokenBuckets qui contiennent des Tokens) et chaque objet (sur une page de détail, ou une page de liste, ou autre) peut demander à TokenBucket de l'utilisateur si un certain niveau de l'accès est autorisé.

Fondamentalement, c'est un type étrange de système ACL. Ce n'était pas si difficile de créer la mécanique. Toute la magie consiste à déterminer dans quelles circonstances les jetons entrent dans le seau.

0

Nous avons utilisé un système de base de rôle pour un problème similaire. Fondamentalement, les utilisateurs ont des autorisations pour assumer différents rôles.

fonctions Voir se sont décorées:

def needs_capability(capability,redirect_to="/cms/"): 
    def view_func_wrapper(view_func): 
     def wrapped_view_func(request,*args,**kwargs): 
      if not request.role._can(capability): 
       return HttpResponseRedirect(redirect_to) 
      return view_func(request,*args,**kwargs) 
     return wrapped_view_func 
    return view_func_wrapper 

Le reste de la magie est à l'intérieur de l'attribut request.role qui a obtenu ensemble à l'intérieur d'un processeur de contexte. Les utilisateurs authentifiés ont un rôle, pour les masses non lavées un DummyRole.

L'accès à l'information a été restreint plus à l'intérieur des modèles:

{% if not request.role.can.view_all_products %} 
      Lots of products, yeah! 
{% endif %} 

pas la solution la plus propre à mon avis, mais a fonctionné comme prévu.

1

Cette question a été posée au octobre 2009 et le problème existe toujours en Juillet 2012.

J'ai cherché une bonne application basée sur les rôles et trouvé django-permission comme le meilleur résultat.

Trois caractéristiques importantes que je avais besoin étaient rôles, vue Décorateurs et Templatetag; apparemment django-permissions a tous. Lisez c'est docs pour son utilisation.

Le seul inconvénient est qu'il est en cours de développement.

Questions connexes