Fixed #4617 -- Added `raise_exception` option to `permission_required` decorator to be able to raise a PermissionDenied exception instead of redirecting to the login page.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@16607 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
1ca6e9b9e2
commit
351d5da69b
|
@ -2,6 +2,7 @@ import urlparse
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.auth import REDIRECT_FIELD_NAME
|
from django.contrib.auth import REDIRECT_FIELD_NAME
|
||||||
|
from django.core.exceptions import PermissionDenied
|
||||||
from django.utils.decorators import available_attrs
|
from django.utils.decorators import available_attrs
|
||||||
|
|
||||||
|
|
||||||
|
@ -47,9 +48,20 @@ def login_required(function=None, redirect_field_name=REDIRECT_FIELD_NAME, login
|
||||||
return actual_decorator
|
return actual_decorator
|
||||||
|
|
||||||
|
|
||||||
def permission_required(perm, login_url=None):
|
def permission_required(perm, login_url=None, raise_exception=False):
|
||||||
"""
|
"""
|
||||||
Decorator for views that checks whether a user has a particular permission
|
Decorator for views that checks whether a user has a particular permission
|
||||||
enabled, redirecting to the log-in page if necessary.
|
enabled, redirecting to the log-in page if neccesary.
|
||||||
|
If the raise_exception parameter is given the PermissionDenied exception
|
||||||
|
is raised.
|
||||||
"""
|
"""
|
||||||
return user_passes_test(lambda u: u.has_perm(perm), login_url=login_url)
|
def check_perms(user):
|
||||||
|
# First check if the user has the permission (even anon users)
|
||||||
|
if user.has_perm(perm):
|
||||||
|
return True
|
||||||
|
# In case the 403 handler should be called raise the exception
|
||||||
|
if raise_exception:
|
||||||
|
raise PermissionDenied
|
||||||
|
# As the last resort, show the login form
|
||||||
|
return False
|
||||||
|
return user_passes_test(check_perms, login_url=login_url)
|
||||||
|
|
|
@ -1167,7 +1167,7 @@ checks to make sure the user is logged in and has the permission
|
||||||
return HttpResponse("You can't vote in this poll.")
|
return HttpResponse("You can't vote in this poll.")
|
||||||
# ...
|
# ...
|
||||||
|
|
||||||
.. function:: user_passes_test()
|
.. function:: user_passes_test(func, [login_url=None])
|
||||||
|
|
||||||
As a shortcut, you can use the convenient ``user_passes_test`` decorator::
|
As a shortcut, you can use the convenient ``user_passes_test`` decorator::
|
||||||
|
|
||||||
|
@ -1205,7 +1205,7 @@ checks to make sure the user is logged in and has the permission
|
||||||
The permission_required decorator
|
The permission_required decorator
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
.. function:: permission_required()
|
.. function:: permission_required([login_url=None, raise_exception=False])
|
||||||
|
|
||||||
It's a relatively common task to check whether a user has a particular
|
It's a relatively common task to check whether a user has a particular
|
||||||
permission. For that reason, Django provides a shortcut for that case: the
|
permission. For that reason, Django provides a shortcut for that case: the
|
||||||
|
@ -1234,6 +1234,13 @@ The permission_required decorator
|
||||||
As in the :func:`~decorators.login_required` decorator, ``login_url``
|
As in the :func:`~decorators.login_required` decorator, ``login_url``
|
||||||
defaults to :setting:`settings.LOGIN_URL <LOGIN_URL>`.
|
defaults to :setting:`settings.LOGIN_URL <LOGIN_URL>`.
|
||||||
|
|
||||||
|
.. versionchanged:: 1.4
|
||||||
|
|
||||||
|
Added ``raise_exception`` parameter. If given, the decorator will raise
|
||||||
|
:exc:`~django.core.exceptions.PermissionDenied`, prompting
|
||||||
|
:ref:`the 403 (HTTP Forbidden) view<http_forbidden_view>` instead of
|
||||||
|
redirecting to the login page.
|
||||||
|
|
||||||
.. currentmodule:: django.contrib.auth
|
.. currentmodule:: django.contrib.auth
|
||||||
|
|
||||||
Limiting access to generic views
|
Limiting access to generic views
|
||||||
|
@ -1632,6 +1639,8 @@ the ``auth_permission`` table most of the time.
|
||||||
|
|
||||||
.. _django/contrib/auth/backends.py: http://code.djangoproject.com/browser/django/trunk/django/contrib/auth/backends.py
|
.. _django/contrib/auth/backends.py: http://code.djangoproject.com/browser/django/trunk/django/contrib/auth/backends.py
|
||||||
|
|
||||||
|
.. _anonymous_auth:
|
||||||
|
|
||||||
Authorization for anonymous users
|
Authorization for anonymous users
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
|
|
@ -370,6 +370,21 @@ class ClientTest(TestCase):
|
||||||
|
|
||||||
# TODO: Log in with right permissions and request the page again
|
# TODO: Log in with right permissions and request the page again
|
||||||
|
|
||||||
|
def test_view_with_permissions_exception(self):
|
||||||
|
"Request a page that is protected with @permission_required but raises a exception"
|
||||||
|
|
||||||
|
# Get the page without logging in. Should result in 403.
|
||||||
|
response = self.client.get('/test_client/permission_protected_view_exception/')
|
||||||
|
self.assertEquals(response.status_code, 403)
|
||||||
|
|
||||||
|
# Log in
|
||||||
|
login = self.client.login(username='testclient', password='password')
|
||||||
|
self.assertTrue(login, 'Could not log in')
|
||||||
|
|
||||||
|
# Log in with wrong permissions. Should result in 403.
|
||||||
|
response = self.client.get('/test_client/permission_protected_view_exception/')
|
||||||
|
self.assertEquals(response.status_code, 403)
|
||||||
|
|
||||||
def test_view_with_method_permissions(self):
|
def test_view_with_method_permissions(self):
|
||||||
"Request a page that is protected with a @permission_required method"
|
"Request a page that is protected with a @permission_required method"
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@ urlpatterns = patterns('',
|
||||||
(r'^login_protected_method_view/$', views.login_protected_method_view),
|
(r'^login_protected_method_view/$', views.login_protected_method_view),
|
||||||
(r'^login_protected_view_custom_redirect/$', views.login_protected_view_changed_redirect),
|
(r'^login_protected_view_custom_redirect/$', views.login_protected_view_changed_redirect),
|
||||||
(r'^permission_protected_view/$', views.permission_protected_view),
|
(r'^permission_protected_view/$', views.permission_protected_view),
|
||||||
|
(r'^permission_protected_view_exception/$', views.permission_protected_view_exception),
|
||||||
(r'^permission_protected_method_view/$', views.permission_protected_method_view),
|
(r'^permission_protected_method_view/$', views.permission_protected_method_view),
|
||||||
(r'^session_view/$', views.session_view),
|
(r'^session_view/$', views.session_view),
|
||||||
(r'^broken_view/$', views.broken_view),
|
(r'^broken_view/$', views.broken_view),
|
||||||
|
|
|
@ -143,7 +143,7 @@ def login_protected_view_changed_redirect(request):
|
||||||
return HttpResponse(t.render(c))
|
return HttpResponse(t.render(c))
|
||||||
login_protected_view_changed_redirect = login_required(redirect_field_name="redirect_to")(login_protected_view_changed_redirect)
|
login_protected_view_changed_redirect = login_required(redirect_field_name="redirect_to")(login_protected_view_changed_redirect)
|
||||||
|
|
||||||
def permission_protected_view(request):
|
def _permission_protected_view(request):
|
||||||
"A simple view that is permission protected."
|
"A simple view that is permission protected."
|
||||||
t = Template('This is a permission protected test. '
|
t = Template('This is a permission protected test. '
|
||||||
'Username is {{ user.username }}. '
|
'Username is {{ user.username }}. '
|
||||||
|
@ -151,7 +151,8 @@ def permission_protected_view(request):
|
||||||
name='Permissions Template')
|
name='Permissions Template')
|
||||||
c = Context({'user': request.user})
|
c = Context({'user': request.user})
|
||||||
return HttpResponse(t.render(c))
|
return HttpResponse(t.render(c))
|
||||||
permission_protected_view = permission_required('modeltests.test_perm')(permission_protected_view)
|
permission_protected_view = permission_required('modeltests.test_perm')(_permission_protected_view)
|
||||||
|
permission_protected_view_exception = permission_required('modeltests.test_perm', raise_exception=True)(_permission_protected_view)
|
||||||
|
|
||||||
class _ViewManager(object):
|
class _ViewManager(object):
|
||||||
@method_decorator(login_required)
|
@method_decorator(login_required)
|
||||||
|
|
Loading…
Reference in New Issue