Django role based views?

2019-01-16 02:25发布

I'm looking for some input on how others would architect this. I'm going to provide class (django group) based views.

For example, a user's group will determine what views/templates he or she will have access to. I'm thinking of perhaps storing paths to view functions in a table to determine what a user's link bar will consist of. Filter specifications can also be stored to determine what rows will fill these templates.

A good example is a hospital nursing units. Nurses at one unit need not see the entire hospital's patients. They only need to see their patients. Doctors on the same unit need only to see those patients as well, but they should have access to much greater functionality.

Has this been done via some third party application? And how would you approach this problem?

Thanks, Pete

9条回答
欢心
2楼-- · 2019-01-16 03:06

This question has been asked in Oct 2009 and the problem still exists in July 2012.

I have searched for a good Role-Based app, and found django-permission as the best result.

Three important features that I needed were Roles, view Decorators and Templatetag; apparently django-permissions has all of them. Read it's docs for it's usage.

The only drawback is that it's under development.

查看更多
我命由我不由天
3楼-- · 2019-01-16 03:08

Django already has a groups and permissions system, which may be sufficient for your purpose.

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

Generally in your code you check if a user has a permission. A user has his own permissions and those of the groups he belongs to. You can administer this pretty easily from the admin console.

There are two parts you need to look at.

  1. Check that a user requesting a page has permission to do so.
  2. Only display links to the user if he has the permission.

For 1. you can check permissions in a decorator as such:

from django.contrib.auth.decorators import permission_required

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

For 2. the currently logged-in user's permissions are stored in the template variable {{ perms }}. This code checks the same permission as above.

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

To generate a list of links you can iterate over user.get_all_permissions() and fetch the links (or function that generates the link) from a 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), [])

There are probably many other approaches.

查看更多
我欲成王,谁敢阻挡
4楼-- · 2019-01-16 03:14

I had a similar problem not too long ago. Our solution did the trick, though it might be too simple for your situation. Like everyone is suggesting, we used the django permission system to control what user interactions with models. However, we didn't just try to group users, we also grouped objects through a GenericForeignKey.

We built a model that linked to itself to allow for hierarchies to be developed.

class Group( models.Model ):
    name = models.CharField( ... )
    parent = models.ForeignKey( 'self', blank=True, null=True)
    content_type = models.ForeignKey( ContentType )
    object_id = models.PositiveIntegerField()
    content_object = generic.GenericForeignKey( 'content_type', 'object_id' )
    ...

To make it work, we also created a model to serve as the django User model's user profile. All it contained was a ManyToManyField linked to the Group model above. This allowed us to give users access to zero or more Groups as required. (documentation)

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

This gave us the best of both worlds and kept us from trying to shoehorn everything into django's permission system. I'm using this basic setup to control user's access to sports content (some users can access whole leagues, some only one or two conferences, some only have access to individual teams), and it works well in that situation. It could probably be a generalized enough to fit your needs.

查看更多
一纸荒年 Trace。
5楼-- · 2019-01-16 03:15

If you don't need real per-object ACLs, then you can just use the Django permission system. To get a list of all available permissions:

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

There is an API for other authentication and authorization sources, so you do not need to stick with this permissions table.

You may hack this Django system to fit your needs in terms of this authorization model (RBAC) or you may come up with an ACL-like solution.

查看更多
萌系小妹纸
6楼-- · 2019-01-16 03:17

We used a role base system for a similar problem. Basically users have permissions to assume different roles.

View functions got decorated:

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

The rest of the magic is inside the request.role attribute which got set inside a context processor. Authenticated users got a Role, for the unwashed masses a DummyRole.

Access to information was restricted further inside the templates:

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

Not the cleanest solution in my opinion, but worked as expected.

查看更多
唯我独甜
7楼-- · 2019-01-16 03:18
登录 后发表回答