-
-
Notifications
You must be signed in to change notification settings - Fork 31.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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.
- Loading branch information
Showing
6 changed files
with
548 additions
and
35 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.