Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Possible to use decorators in django to do permissions based on a view parameter?

I'm not sure it's possible, but is there a way to write something like

@group_required('group_id')
def myview(request, group_id):
    .....

Where I look at the value of the parameter group_id and limit access to this view to only people who are in this group?

I know it is possible to create a decorator to check membership in some specific group

@group_required('admin')
def myview(request):
   ....

But say I want a view that is only accessible to people within a certain group, which is determined by the url.

So for example

/group/1
/group/2

Should each have permissions so that only members of group #X can see that page. I can easily write this functionality within the view

group = get group
if user not in group
    raise 404

but that logic is repeated all over. Decorators seems like a promising way to do it, but it seems the scope is backwards. Is there another preferred way to handle this sort of permissions?

Thanks!

like image 949
jkeesh Avatar asked Jan 03 '14 10:01

jkeesh


2 Answers

The decorator has access to all the view arguments, so it's definitely possible. You could do this:

def group_required(arg_name):
    def decorator(view):
        def wrapper(request, *args, **kwargs):
            group_id = kwargs.get(arg_name)
            user = request.user
            if group_id in user.groups.values_list('id', flat=True):
                return view(request, *args, **kwargs)
            else:
                return HttpResponseForbidden # 403 Forbidden is better than 404
        return wrapper
    return decorator

(If you don't need the flexibility of dynamically defining the argument in the decorator, eg if you always call it group_id, you can miss out the outer function here and just use kwargs.get('group_id').)

like image 152
Daniel Roseman Avatar answered Sep 28 '22 03:09

Daniel Roseman


Daniel's answer appears to not work on Django 1.11. Here's a modified version:

def group_required(group_name):
    def decorator(view):
        @functools.wraps(view)
        def wrapper(request, *args, **kwargs):
            if (request.user.groups.filter(name=group_name).exists() or
                    request.user.is_superuser):
                return view(request, *args, **kwargs)
            else:
                return HttpResponseForbidden("You don't have permission to view this page.")
        return wrapper
    return decorator
like image 33
Turtles Are Cute Avatar answered Sep 28 '22 04:09

Turtles Are Cute