diff options
| author | Berker Peksag <berker.peksag@gmail.com> | 2016-08-25 19:26:18 +0300 |
|---|---|---|
| committer | Mariusz Felisiak <felisiak.mariusz@gmail.com> | 2019-08-29 19:32:12 +0200 |
| commit | 400ec5125ec32e3b18d267bbb4f3aab09d741ce4 (patch) | |
| tree | 96ef0b85d3dc5b7ea132307ab7fc1f6683201905 /django | |
| parent | fa7ffc6cb3b143fb8566cbf6a387d0f032377dc7 (diff) | |
Fixed #18763 -- Added ModelBackend/UserManager.with_perm() methods.
Co-authored-by: Nick Pope <nick.pope@flightdataservices.com>
Diffstat (limited to 'django')
| -rw-r--r-- | django/contrib/auth/backends.py | 37 | ||||
| -rw-r--r-- | django/contrib/auth/models.py | 26 |
2 files changed, 63 insertions, 0 deletions
diff --git a/django/contrib/auth/backends.py b/django/contrib/auth/backends.py index a3765ae0f1..559d06fe33 100644 --- a/django/contrib/auth/backends.py +++ b/django/contrib/auth/backends.py @@ -3,6 +3,7 @@ import warnings from django.contrib.auth import get_user_model from django.contrib.auth.models import Permission +from django.db.models import Exists, OuterRef, Q from django.utils.deprecation import RemovedInDjango31Warning UserModel = get_user_model() @@ -119,6 +120,42 @@ class ModelBackend(BaseBackend): for perm in self.get_all_permissions(user_obj) ) + def with_perm(self, perm, is_active=True, include_superusers=True, obj=None): + """ + Return users that have permission "perm". By default, filter out + inactive users and include superusers. + """ + if isinstance(perm, str): + try: + app_label, codename = perm.split('.') + except ValueError: + raise ValueError( + 'Permission name should be in the form ' + 'app_label.permission_codename.' + ) + elif not isinstance(perm, Permission): + raise TypeError( + 'The `perm` argument must be a string or a permission instance.' + ) + + UserModel = get_user_model() + if obj is not None: + return UserModel._default_manager.none() + + permission_q = Q(group__user=OuterRef('pk')) | Q(user=OuterRef('pk')) + if isinstance(perm, Permission): + permission_q &= Q(pk=perm.pk) + else: + permission_q &= Q(codename=codename, content_type__app_label=app_label) + + user_q = Exists(Permission.objects.filter(permission_q)) + if include_superusers: + user_q |= Q(is_superuser=True) + if is_active is not None: + user_q &= Q(is_active=is_active) + + return UserModel._default_manager.filter(user_q) + def get_user(self, user_id): try: user = UserModel._default_manager.get(pk=user_id) diff --git a/django/contrib/auth/models.py b/django/contrib/auth/models.py index 971621d9c7..27278af4d2 100644 --- a/django/contrib/auth/models.py +++ b/django/contrib/auth/models.py @@ -157,6 +157,32 @@ class UserManager(BaseUserManager): return self._create_user(username, email, password, **extra_fields) + def with_perm(self, perm, is_active=True, include_superusers=True, backend=None, obj=None): + if backend is None: + backends = auth._get_backends(return_tuples=True) + if len(backends) == 1: + backend, _ = backends[0] + else: + raise ValueError( + 'You have multiple authentication backends configured and ' + 'therefore must provide the `backend` argument.' + ) + elif not isinstance(backend, str): + raise TypeError( + 'backend must be a dotted import path string (got %r).' + % backend + ) + else: + backend = auth.load_backend(backend) + if hasattr(backend, 'with_perm'): + return backend.with_perm( + perm, + is_active=is_active, + include_superusers=include_superusers, + obj=obj, + ) + return self.none() + # A few helper functions for common logic between User and AnonymousUser. def _user_get_permissions(user, obj, from_name): |
