summaryrefslogtreecommitdiff
path: root/django
diff options
context:
space:
mode:
authorMarkus Holtermann <info@markusholtermann.eu>2015-06-11 18:08:48 +0200
committerMarkus Holtermann <info@markusholtermann.eu>2015-06-17 23:19:10 +0200
commite5cb4e14118f3a508e3bc00ee7cd50bb0f18a61d (patch)
treecc079646b4db9f528366c59d67768584387531cd /django
parent2f615b10e6330d27dccbd770a4628200044acf70 (diff)
Fixed #24914 -- Added authentication mixins for CBVs
Added the mixins LoginRequiredMixin, PermissionRequiredMixin and UserPassesTestMixin to contrib.auth as counterparts to the respective view decorators. The authentication mixins UserPassesTestMixin, LoginRequiredMixin and PermissionRequiredMixin have been inspired by django-braces <https://github.com/brack3t/django-braces/> Thanks Raphael Michel for the initial patch, tests and docs on the PR and Ana Balica, Kenneth Love, Marc Tamlyn, and Tim Graham for the review.
Diffstat (limited to 'django')
-rw-r--r--django/contrib/auth/mixins.py110
1 files changed, 110 insertions, 0 deletions
diff --git a/django/contrib/auth/mixins.py b/django/contrib/auth/mixins.py
new file mode 100644
index 0000000000..00fc9cb727
--- /dev/null
+++ b/django/contrib/auth/mixins.py
@@ -0,0 +1,110 @@
+from django.conf import settings
+from django.contrib.auth import REDIRECT_FIELD_NAME
+from django.contrib.auth.views import redirect_to_login
+from django.core.exceptions import ImproperlyConfigured, PermissionDenied
+from django.utils import six
+from django.utils.encoding import force_text
+
+
+class AccessMixin(object):
+ """
+ Abstract CBV mixin that gives access mixins the same customizable
+ functionality.
+ """
+ login_url = None
+ permission_denied_message = ''
+ raise_exception = False
+ redirect_field_name = REDIRECT_FIELD_NAME
+
+ def get_login_url(self):
+ """
+ Override this method to override the login_url attribute.
+ """
+ login_url = self.login_url or settings.LOGIN_URL
+ if not login_url:
+ raise ImproperlyConfigured(
+ '{0} is missing the login_url attribute. Define {0}.login_url, settings.LOGIN_URL, or override '
+ '{0}.get_login_url().'.format(self.__class__.__name__)
+ )
+ return force_text(login_url)
+
+ def get_permission_denied_message(self):
+ """
+ Override this method to override the permission_denied_message attribute.
+ """
+ return self.permission_denied_message
+
+ def get_redirect_field_name(self):
+ """
+ Override this method to override the redirect_field_name attribute.
+ """
+ return self.redirect_field_name
+
+ def handle_no_permission(self):
+ if self.raise_exception:
+ raise PermissionDenied(self.get_permission_denied_message())
+ return redirect_to_login(self.request.get_full_path(), self.get_login_url(), self.get_redirect_field_name())
+
+
+class LoginRequiredMixin(AccessMixin):
+ """
+ CBV mixin which verifies that the current user is authenticated.
+ """
+ def dispatch(self, request, *args, **kwargs):
+ if not request.user.is_authenticated():
+ return self.handle_no_permission()
+ return super(LoginRequiredMixin, self).dispatch(request, *args, **kwargs)
+
+
+class PermissionRequiredMixin(AccessMixin):
+ """
+ CBV mixin which verifies that the current user has all specified
+ permissions.
+ """
+ permission_required = None
+
+ def get_permission_required(self):
+ """
+ Override this method to override the permission_required attribute.
+ Must return an iterable.
+ """
+ if self.permission_required is None:
+ raise ImproperlyConfigured(
+ '{0} is missing the permission_required attribute. Define {0}.permission_required, or override '
+ '{0}.get_permission_required().'.format(self.__class__.__name__)
+ )
+ if isinstance(self.permission_required, six.string_types):
+ perms = (self.permission_required, )
+ else:
+ perms = self.permission_required
+ return perms
+
+ def dispatch(self, request, *args, **kwargs):
+ perms = self.get_permission_required()
+ if not request.user.has_perms(perms):
+ return self.handle_no_permission()
+ return super(PermissionRequiredMixin, self).dispatch(request, *args, **kwargs)
+
+
+class UserPassesTestMixin(AccessMixin):
+ """
+ CBV Mixin that allows you to define a test function which must return True
+ if the current user can access the view.
+ """
+
+ def test_func(self):
+ raise NotImplementedError(
+ '{0} is missing the implementation of the test_func() method.'.format(self.__class__.__name__)
+ )
+
+ def get_test_func(self):
+ """
+ Override this method to use a different test_func method.
+ """
+ return self.test_func
+
+ def dispatch(self, request, *args, **kwargs):
+ user_test_result = self.get_test_func()()
+ if not user_test_result:
+ return self.handle_no_permission()
+ return super(UserPassesTestMixin, self).dispatch(request, *args, **kwargs)