Refs #30226 -- Added User.get_user_permissions() method.

Added to mirror the existing User.get_group_permissions().
This commit is contained in:
Tobias Bengfort 2019-03-24 00:40:44 +01:00 committed by Mariusz Felisiak
parent 75337a6050
commit 581a0f4545
7 changed files with 70 additions and 22 deletions

View File

@ -15,11 +15,17 @@ class BaseBackend:
def get_user(self, user_id): def get_user(self, user_id):
return None return None
def get_user_permissions(self, user_obj, obj=None):
return set()
def get_group_permissions(self, user_obj, obj=None): def get_group_permissions(self, user_obj, obj=None):
return set() return set()
def get_all_permissions(self, user_obj, obj=None): def get_all_permissions(self, user_obj, obj=None):
return self.get_group_permissions(user_obj, obj=obj) return {
*self.get_user_permissions(user_obj, obj=obj),
*self.get_group_permissions(user_obj, obj=obj),
}
def has_perm(self, user_obj, perm, obj=None): def has_perm(self, user_obj, perm, obj=None):
return perm in self.get_all_permissions(user_obj, obj=obj) return perm in self.get_all_permissions(user_obj, obj=obj)
@ -96,10 +102,7 @@ class ModelBackend(BaseBackend):
if not user_obj.is_active or user_obj.is_anonymous or obj is not None: if not user_obj.is_active or user_obj.is_anonymous or obj is not None:
return set() return set()
if not hasattr(user_obj, '_perm_cache'): if not hasattr(user_obj, '_perm_cache'):
user_obj._perm_cache = { user_obj._perm_cache = super().get_all_permissions(user_obj)
*self.get_user_permissions(user_obj),
*self.get_group_permissions(user_obj),
}
return user_obj._perm_cache return user_obj._perm_cache
def has_perm(self, user_obj, perm, obj=None): def has_perm(self, user_obj, perm, obj=None):

View File

@ -159,11 +159,12 @@ class UserManager(BaseUserManager):
# A few helper functions for common logic between User and AnonymousUser. # A few helper functions for common logic between User and AnonymousUser.
def _user_get_all_permissions(user, obj): def _user_get_permissions(user, obj, from_name):
permissions = set() permissions = set()
name = 'get_%s_permissions' % from_name
for backend in auth.get_backends(): for backend in auth.get_backends():
if hasattr(backend, "get_all_permissions"): if hasattr(backend, name):
permissions.update(backend.get_all_permissions(user, obj)) permissions.update(getattr(backend, name)(user, obj))
return permissions return permissions
@ -233,20 +234,24 @@ class PermissionsMixin(models.Model):
class Meta: class Meta:
abstract = True abstract = True
def get_user_permissions(self, obj=None):
"""
Return a list of permission strings that this user has directly.
Query all available auth backends. If an object is passed in,
return only permissions matching this object.
"""
return _user_get_permissions(self, obj, 'user')
def get_group_permissions(self, obj=None): def get_group_permissions(self, obj=None):
""" """
Return a list of permission strings that this user has through their Return a list of permission strings that this user has through their
groups. Query all available auth backends. If an object is passed in, groups. Query all available auth backends. If an object is passed in,
return only permissions matching this object. return only permissions matching this object.
""" """
permissions = set() return _user_get_permissions(self, obj, 'group')
for backend in auth.get_backends():
if hasattr(backend, "get_group_permissions"):
permissions.update(backend.get_group_permissions(self, obj))
return permissions
def get_all_permissions(self, obj=None): def get_all_permissions(self, obj=None):
return _user_get_all_permissions(self, obj) return _user_get_permissions(self, obj, 'all')
def has_perm(self, perm, obj=None): def has_perm(self, perm, obj=None):
""" """
@ -403,11 +408,14 @@ class AnonymousUser:
def user_permissions(self): def user_permissions(self):
return self._user_permissions return self._user_permissions
def get_user_permissions(self, obj=None):
return _user_get_permissions(self, obj, 'user')
def get_group_permissions(self, obj=None): def get_group_permissions(self, obj=None):
return set() return set()
def get_all_permissions(self, obj=None): def get_all_permissions(self, obj=None):
return _user_get_all_permissions(self, obj=obj) return _user_get_permissions(self, obj, 'all')
def has_perm(self, perm, obj=None): def has_perm(self, perm, obj=None):
return _user_has_perm(self, perm, obj=obj) return _user_has_perm(self, perm, obj=obj)

View File

@ -191,6 +191,15 @@ Methods
:meth:`~django.contrib.auth.models.User.set_unusable_password()` has :meth:`~django.contrib.auth.models.User.set_unusable_password()` has
been called for this user. been called for this user.
.. method:: get_user_permissions(obj=None)
.. versionadded:: 3.0
Returns a set of permission strings that the user has directly.
If ``obj`` is passed in, only returns the user permissions for this
specific object.
.. method:: get_group_permissions(obj=None) .. method:: get_group_permissions(obj=None)
Returns a set of permission strings that the user has, through their Returns a set of permission strings that the user has, through their
@ -467,14 +476,18 @@ The following backends are available in :mod:`django.contrib.auth.backends`:
A base class that provides default implementations for all required A base class that provides default implementations for all required
methods. By default, it will reject any user and provide no permissions. methods. By default, it will reject any user and provide no permissions.
.. method:: get_user_permissions(user_obj, obj=None)
Returns an empty set.
.. method:: get_group_permissions(user_obj, obj=None) .. method:: get_group_permissions(user_obj, obj=None)
Returns an empty set. Returns an empty set.
.. method:: get_all_permissions(user_obj, obj=None) .. method:: get_all_permissions(user_obj, obj=None)
Uses :meth:`get_group_permissions` to get the set of permission strings Uses :meth:`get_user_permissions` and :meth:`get_group_permissions` to
the ``user_obj`` has. get the set of permission strings the ``user_obj`` has.
.. method:: has_perm(user_obj, perm, obj=None) .. method:: has_perm(user_obj, perm, obj=None)

View File

@ -72,6 +72,10 @@ Minor features
* Added :class:`~django.contrib.auth.backends.BaseBackend` class to ease * Added :class:`~django.contrib.auth.backends.BaseBackend` class to ease
customization of authentication backends. customization of authentication backends.
* Added :meth:`~django.contrib.auth.models.User.get_user_permissions()` method
to mirror the existing
:meth:`~django.contrib.auth.models.User.get_group_permissions()` method.
:mod:`django.contrib.contenttypes` :mod:`django.contrib.contenttypes`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -180,7 +180,8 @@ Handling authorization in custom backends
Custom auth backends can provide their own permissions. Custom auth backends can provide their own permissions.
The user model will delegate permission lookup functions The user model will delegate permission lookup functions
(:meth:`~django.contrib.auth.models.User.get_group_permissions()`, (:meth:`~django.contrib.auth.models.User.get_user_permissions()`,
:meth:`~django.contrib.auth.models.User.get_group_permissions()`,
:meth:`~django.contrib.auth.models.User.get_all_permissions()`, :meth:`~django.contrib.auth.models.User.get_all_permissions()`,
:meth:`~django.contrib.auth.models.User.has_perm()`, and :meth:`~django.contrib.auth.models.User.has_perm()`, and
:meth:`~django.contrib.auth.models.User.has_module_perms()`) to any :meth:`~django.contrib.auth.models.User.has_module_perms()`) to any
@ -898,6 +899,15 @@ methods and attributes:
Boolean. Designates that this user has all permissions without Boolean. Designates that this user has all permissions without
explicitly assigning them. explicitly assigning them.
.. method:: models.PermissionsMixin.get_user_permissions(obj=None)
.. versionadded:: 3.0
Returns a set of permission strings that the user has directly.
If ``obj`` is passed in, only returns the user permissions for this
specific object.
.. method:: models.PermissionsMixin.get_group_permissions(obj=None) .. method:: models.PermissionsMixin.get_group_permissions(obj=None)
Returns a set of permission strings that the user has, through their Returns a set of permission strings that the user has, through their

View File

@ -21,6 +21,9 @@ from .models import (
class SimpleBackend(BaseBackend): class SimpleBackend(BaseBackend):
def get_user_permissions(self, user_obj, obj=None):
return ['user_perm']
def get_group_permissions(self, user_obj, obj=None): def get_group_permissions(self, user_obj, obj=None):
return ['group_perm'] return ['group_perm']
@ -31,13 +34,17 @@ class BaseBackendTest(TestCase):
def setUpTestData(cls): def setUpTestData(cls):
cls.user = User.objects.create_user('test', 'test@example.com', 'test') cls.user = User.objects.create_user('test', 'test@example.com', 'test')
def test_get_user_permissions(self):
self.assertEqual(self.user.get_user_permissions(), {'user_perm'})
def test_get_group_permissions(self): def test_get_group_permissions(self):
self.assertEqual(self.user.get_group_permissions(), {'group_perm'}) self.assertEqual(self.user.get_group_permissions(), {'group_perm'})
def test_get_all_permissions(self): def test_get_all_permissions(self):
self.assertEqual(self.user.get_all_permissions(), {'group_perm'}) self.assertEqual(self.user.get_all_permissions(), {'user_perm', 'group_perm'})
def test_has_perm(self): def test_has_perm(self):
self.assertIs(self.user.has_perm('user_perm'), True)
self.assertIs(self.user.has_perm('group_perm'), True) self.assertIs(self.user.has_perm('group_perm'), True)
self.assertIs(self.user.has_perm('other_perm', TestObj()), False) self.assertIs(self.user.has_perm('other_perm', TestObj()), False)
@ -102,6 +109,7 @@ class BaseModelBackendTest:
# reloading user to purge the _perm_cache # reloading user to purge the _perm_cache
user = self.UserModel._default_manager.get(pk=self.user.pk) user = self.UserModel._default_manager.get(pk=self.user.pk)
self.assertEqual(user.get_all_permissions(), {'auth.test'}) self.assertEqual(user.get_all_permissions(), {'auth.test'})
self.assertEqual(user.get_user_permissions(), {'auth.test'})
self.assertEqual(user.get_group_permissions(), set()) self.assertEqual(user.get_group_permissions(), set())
self.assertIs(user.has_module_perms('Group'), False) self.assertIs(user.has_module_perms('Group'), False)
self.assertIs(user.has_module_perms('auth'), True) self.assertIs(user.has_module_perms('auth'), True)
@ -111,7 +119,8 @@ class BaseModelBackendTest:
perm = Permission.objects.create(name='test3', content_type=content_type, codename='test3') perm = Permission.objects.create(name='test3', content_type=content_type, codename='test3')
user.user_permissions.add(perm) user.user_permissions.add(perm)
user = self.UserModel._default_manager.get(pk=self.user.pk) user = self.UserModel._default_manager.get(pk=self.user.pk)
self.assertEqual(user.get_all_permissions(), {'auth.test2', 'auth.test', 'auth.test3'}) expected_user_perms = {'auth.test2', 'auth.test', 'auth.test3'}
self.assertEqual(user.get_all_permissions(), expected_user_perms)
self.assertIs(user.has_perm('test'), False) self.assertIs(user.has_perm('test'), False)
self.assertIs(user.has_perm('auth.test'), True) self.assertIs(user.has_perm('auth.test'), True)
self.assertIs(user.has_perms(['auth.test2', 'auth.test3']), True) self.assertIs(user.has_perms(['auth.test2', 'auth.test3']), True)
@ -121,8 +130,8 @@ class BaseModelBackendTest:
group.permissions.add(perm) group.permissions.add(perm)
user.groups.add(group) user.groups.add(group)
user = self.UserModel._default_manager.get(pk=self.user.pk) user = self.UserModel._default_manager.get(pk=self.user.pk)
exp = {'auth.test2', 'auth.test', 'auth.test3', 'auth.test_group'} self.assertEqual(user.get_all_permissions(), {*expected_user_perms, 'auth.test_group'})
self.assertEqual(user.get_all_permissions(), exp) self.assertEqual(user.get_user_permissions(), expected_user_perms)
self.assertEqual(user.get_group_permissions(), {'auth.test_group'}) self.assertEqual(user.get_group_permissions(), {'auth.test_group'})
self.assertIs(user.has_perms(['auth.test3', 'auth.test_group']), True) self.assertIs(user.has_perms(['auth.test3', 'auth.test_group']), True)

View File

@ -333,6 +333,7 @@ class AnonymousUserTests(SimpleTestCase):
self.assertIs(self.user.is_superuser, False) self.assertIs(self.user.is_superuser, False)
self.assertEqual(self.user.groups.all().count(), 0) self.assertEqual(self.user.groups.all().count(), 0)
self.assertEqual(self.user.user_permissions.all().count(), 0) self.assertEqual(self.user.user_permissions.all().count(), 0)
self.assertEqual(self.user.get_user_permissions(), set())
self.assertEqual(self.user.get_group_permissions(), set()) self.assertEqual(self.user.get_group_permissions(), set())
def test_str(self): def test_str(self):