10

In my Django application, I have certain permissions which users need in order to access certain views (using django.contrib.auth). This works fine, using the @permission_required decorator on my view functions.

However, some of my URLs resolve to views which I did not write, such as the built-in django.contrib.auth.views.password_change, as in the following urls.py:

urlpatterns = patterns(
 (r'^$', "users.views.index"),
 (r'^password_change/$', 'django.contrib.auth.views.password_change'))

In this instance, I have nowhere to apply my @permission_required decorator -- or do I? Is there any way to apply a permissions restriction at the URL dispatcher level?

Manoj Govindan
  • 72,339
  • 21
  • 134
  • 141
kdt
  • 27,905
  • 33
  • 92
  • 139

4 Answers4

17

A decorator is a fancy word for a function that wraps another function. login_required is a wrapper function for a view while permission_required constructs a wrapper for your view. In other words, login_required is itself a decorator and permission_required(perm) constructs a decorator.

from django.conf.urls import url
from django.contrib.auth.decorators import login_required, permission_required

urlpatterns = [
    url(r'^public/', myview),

    url(r'^users_only/', 
        login_required(myview)),

    url(r'^users_with_perms/',
        permission_required('myapp.view_mymodel', login_url='login')(myview)),

    url(r'^login_page/', myloginview, name='login'),
]
jozxyqk
  • 16,424
  • 12
  • 91
  • 180
10

It's possible to import the login required function and apply it to the generic view:

from django.contrib.auth.decorators import login_required
from django.views.generic.simple import direct_to_template
urlpatterns = patterns('',
    (r'^foo/$', login_required(direct_to_template), {'template': 'foo_index.html'}),
    )

as mention here.

Community
  • 1
  • 1
Hoff
  • 38,776
  • 17
  • 74
  • 99
  • How would you use `permission_required` in the same way? Specifically how would you pass it the permission name argument? – Manoj Govindan Aug 12 '10 at 11:43
  • @Manoj: check out this section of the documentation: http://docs.djangoproject.com/en/dev/topics/auth/#limiting-access-to-generic-views the idea is to write a thin wrapper (with permission_required decorator) around the generic view, and point your urlconf to that wrapper... – Hoff Aug 13 '10 at 10:13
  • That is what I did in my answer. Just wanted to know if there was any other way to go about it. Thanks. – Manoj Govindan Aug 13 '10 at 10:20
  • I need a customized decorator, how can I create a customized permission check function to wrap the view function, thanks. – Alston Oct 04 '16 at 15:13
  • @stallman just write your own decorator, import it, and use it in place of login_required. A decorators really is just a function, and can be used like one... – Hoff Oct 06 '16 at 16:04
-1

One approach would be to wrap the views you did not write.

from django.contrib.auth.views import password_change

@permission_required('my_perm')
def wrapper(*args, **kwargs):
    return password_change(*args, **kwargs)

#URLs
urlpatterns = patterns(
  (r'^$', "users.views.index"),
  (r'^password_change/$', 'wrapper'))
Manoj Govindan
  • 72,339
  • 21
  • 134
  • 141
-2

I have a little hack about the Django URL resolver, you may apply a decorator at URL dispatch level:

from django_url_decr import url_decr
from django.contrib.auth.decorators import login_required

urlpatterns = patterns(''
                       url_decr(r'^users/',
                                include('users.urls'),
                                decr=login_required))
honk
  • 9,137
  • 11
  • 75
  • 83
socrates
  • 1,203
  • 11
  • 16