mirror of
				https://github.com/django/django.git
				synced 2025-10-26 07:06:08 +00:00 
			
		
		
		
	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:
		| @@ -2,6 +2,7 @@ import urlparse | ||||
| from functools import wraps | ||||
| from django.conf import settings | ||||
| from django.contrib.auth import REDIRECT_FIELD_NAME | ||||
| from django.core.exceptions import PermissionDenied | ||||
| 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 | ||||
|  | ||||
|  | ||||
| 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 | ||||
|     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.") | ||||
|         # ... | ||||
|  | ||||
| .. function:: user_passes_test() | ||||
| .. function:: user_passes_test(func, [login_url=None]) | ||||
|  | ||||
|     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 | ||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||||
|  | ||||
| .. 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 | ||||
|     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`` | ||||
|     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 | ||||
|  | ||||
| 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 | ||||
|  | ||||
| .. _anonymous_auth: | ||||
|  | ||||
| Authorization for anonymous users | ||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||||
|  | ||||
|   | ||||
| @@ -370,6 +370,21 @@ class ClientTest(TestCase): | ||||
|  | ||||
|         # 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): | ||||
|         "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_view_custom_redirect/$', views.login_protected_view_changed_redirect), | ||||
|     (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'^session_view/$', views.session_view), | ||||
|     (r'^broken_view/$', views.broken_view), | ||||
|   | ||||
| @@ -143,7 +143,7 @@ def login_protected_view_changed_redirect(request): | ||||
|     return HttpResponse(t.render(c)) | ||||
| 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." | ||||
|     t = Template('This is a permission protected test. ' | ||||
|                  'Username is {{ user.username }}. ' | ||||
| @@ -151,7 +151,8 @@ def permission_protected_view(request): | ||||
|                  name='Permissions Template') | ||||
|     c = Context({'user': request.user}) | ||||
|     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): | ||||
|     @method_decorator(login_required) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user