jezdez / django-authority (http://packages.python.org/django-authority/)

A Django app that provides generic per-object-permissions for Django's auth app and helpers to create custom permission checks.

Clone this repository (size: 338.3 KB): HTTPS / SSH
$ hg clone http://bitbucket.org/jezdez/django-authority/
commit 28: 00f8b83e5397
parent 27: 8cd5342dd03b
branch: default
Fixed decorator to only check for permissions if user is logged in. Added permission_denied view to be used when permission check unsuccessful, e.g. with the new permission_required_or_403 decorator. The permission_required decorator will redirect to the login form by default.
Jannis Leidel / jezdez
9 months ago

Changed (Δ1.3 KB):

raw changeset »

example/exampleapp/views.py (2 lines added, 1 lines removed)

src/authority/decorators.py (35 lines added, 24 lines removed)

src/authority/views.py (19 lines added, 0 lines removed)

Up to file-list example/exampleapp/views.py:

1
1
from django.contrib.flatpages.views import flatpage
2
2
from django.contrib.flatpages.models import FlatPage
3
3
4
from authority.decorators import permission_required
4
from authority.decorators import permission_required, permission_required_or_403
5
5
6
#@permission_required_or_403('flatpage_permission.top_secret', (FlatPage, 'url__contains')) # use this to return a 403 page
6
7
@permission_required('flatpage_permission.top_secret', (FlatPage, 'url__contains'))
7
8
def top_secret(request, url):
8
9
    """

Up to file-list src/authority/decorators.py:

@@ -10,38 +10,49 @@ from django.contrib.auth.decorators impo
10
10
from django.contrib.auth import REDIRECT_FIELD_NAME
11
11
12
12
from authority import permissions
13
from authority.views import permission_denied
13
14
14
15
def permission_required(perm, *args, **kwargs):
15
16
    """
16
17
    Decorator for views that checks whether a user has a particular permission
17
18
    enabled, redirecting to the log-in page if necessary.
18
19
    """
19
    login_url = kwargs.pop('login_url', None)
20
    if not login_url:
21
        login_url = getattr(settings, 'LOGIN_URL', '/')
20
    login_url = kwargs.pop('login_url', settings.LOGIN_URL)
22
21
    redirect_field_name = kwargs.pop('redirect_field_name', REDIRECT_FIELD_NAME)
22
    redirect_to_login = kwargs.pop('redirect_to_login', True)
23
23
    model_lookups = args
24
24
    def _permission_required(view_func, request, *args, **kwargs):
25
25
        objs = []
26
        # model_lookups = [('flatpages.flatpage', 'url__contains')]
27
        for i, arguments in enumerate(model_lookups):
28
            model, lookup = arguments
29
            if isinstance(model, basestring):
30
                model_class = get_model(*model.split("."))
31
            else:
32
                model_class = model
33
            if model_class is None:
34
                raise ValueError(
35
                    "The given argument '%s' is not a valid model." % model)
36
            if inspect.isclass(model_class) and \
37
                    not issubclass(model_class, Model):
38
                raise ValueError(
39
                    'The argument %s needs to be a model.' % model)
40
            objs.append(get_object_or_404(model_class, **{lookup: args[i]}))
41
        check = permissions.registry.get_check(request.user, perm)
42
        if check is not None:
43
            if check(*objs):
44
                return view_func(request, *args, **kwargs)
45
        #return HttpResponseForbidden("Permission")
46
        raise PermissionDenied()
26
        if request.user.is_authenticated():
27
            for i, arguments in enumerate(model_lookups):
28
                model, lookup = arguments
29
                if isinstance(model, basestring):
30
                    model_class = get_model(*model.split("."))
31
                else:
32
                    model_class = model
33
                if model_class is None:
34
                    raise ValueError(
35
                        "The given argument '%s' is not a valid model." % model)
36
                if inspect.isclass(model_class) and \
37
                        not issubclass(model_class, Model):
38
                    raise ValueError(
39
                        'The argument %s needs to be a model.' % model)
40
                objs.append(get_object_or_404(model_class, **{lookup: args[i]}))
41
            check = permissions.registry.get_check(request.user, perm)
42
            if check is not None:
43
                if check(*objs):
44
                    return view_func(request, *args, **kwargs)
45
        if redirect_to_login:
46
            path = urlquote(request.get_full_path())
47
            tup = login_url, redirect_field_name, path
48
            return HttpResponseRedirect('%s?%s=%s' % tup)
49
        return permission_denied(request)
47
50
    return decorator(_permission_required)
51
52
def permission_required_or_403(perm, *args, **kwargs):
53
    """
54
    Decorator that wraps the permission_required decorator and returns a
55
    permission denied (403) page instead of redirecting to the login URL.
56
    """
57
    kwargs['redirect_to_login'] = False
58
    return permission_required(perm, *args, **kwargs)

Up to file-list src/authority/views.py:

@@ -5,6 +5,7 @@ from django.db.models.loading import get
5
5
from django.core.urlresolvers import reverse
6
6
from django.utils.translation import ugettext, ugettext_lazy as _
7
7
from django.template.context import RequestContext
8
from django.template import loader
8
9
from django.contrib.auth.decorators import login_required
9
10
10
11
from authority.models import Permission
@@ -56,3 +57,21 @@ def delete_permission(request, permissio
56
57
            message=ugettext('You removed the permission.'))
57
58
    next = request.REQUEST.get('next') or '/'
58
59
    return HttpResponseRedirect(next)
60
61
def permission_denied(request, template_name=None, extra_context={}):
62
    """
63
    Default 403 handler.
64
65
    Templates: `403.html`
66
    Context:
67
        request_path
68
            The path of the requested URL (e.g., '/app/pages/bad_page/')
69
    """
70
    if template_name is None:
71
       template_name = ('authority/403.html', '403.html')
72
    context = {
73
        'request_path': request.path,
74
    }
75
    context.update(extra_context)
76
    return HttpResponseForbidden(loader.render_to_string(template_name, context,
77
                                 context_instance=RequestContext(request)))