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):
return None
def get_user_permissions(self, user_obj, obj=None):
return set()
def get_group_permissions(self, user_obj, obj=None):
return set()
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):
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:
return set()
if not hasattr(user_obj, '_perm_cache'):
user_obj._perm_cache = {
*self.get_user_permissions(user_obj),
*self.get_group_permissions(user_obj),
}
user_obj._perm_cache = super().get_all_permissions(user_obj)
return user_obj._perm_cache
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.
def _user_get_all_permissions(user, obj):
def _user_get_permissions(user, obj, from_name):
permissions = set()
name = 'get_%s_permissions' % from_name
for backend in auth.get_backends():
if hasattr(backend, "get_all_permissions"):
permissions.update(backend.get_all_permissions(user, obj))
if hasattr(backend, name):
permissions.update(getattr(backend, name)(user, obj))
return permissions
@ -233,20 +234,24 @@ class PermissionsMixin(models.Model):
class Meta:
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):
"""
Return a list of permission strings that this user has through their
groups. Query all available auth backends. If an object is passed in,
return only permissions matching this object.
"""
permissions = set()
for backend in auth.get_backends():
if hasattr(backend, "get_group_permissions"):
permissions.update(backend.get_group_permissions(self, obj))
return permissions
return _user_get_permissions(self, obj, 'group')
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):
"""
@ -403,11 +408,14 @@ class AnonymousUser:
def user_permissions(self):
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):
return set()
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):
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
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)
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
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)
Returns an empty set.
.. method:: get_all_permissions(user_obj, obj=None)
Uses :meth:`get_group_permissions` to get the set of permission strings
the ``user_obj`` has.
Uses :meth:`get_user_permissions` and :meth:`get_group_permissions` to
get the set of permission strings the ``user_obj`` has.
.. 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
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`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -180,7 +180,8 @@ Handling authorization in custom backends
Custom auth backends can provide their own permissions.
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.has_perm()`, and
: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
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)
Returns a set of permission strings that the user has, through their

View File

@ -21,6 +21,9 @@ from .models import (
class SimpleBackend(BaseBackend):
def get_user_permissions(self, user_obj, obj=None):
return ['user_perm']
def get_group_permissions(self, user_obj, obj=None):
return ['group_perm']
@ -31,13 +34,17 @@ class BaseBackendTest(TestCase):
def setUpTestData(cls):
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):
self.assertEqual(self.user.get_group_permissions(), {'group_perm'})
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):
self.assertIs(self.user.has_perm('user_perm'), True)
self.assertIs(self.user.has_perm('group_perm'), True)
self.assertIs(self.user.has_perm('other_perm', TestObj()), False)
@ -102,6 +109,7 @@ class BaseModelBackendTest:
# reloading user to purge the _perm_cache
user = self.UserModel._default_manager.get(pk=self.user.pk)
self.assertEqual(user.get_all_permissions(), {'auth.test'})
self.assertEqual(user.get_user_permissions(), {'auth.test'})
self.assertEqual(user.get_group_permissions(), set())
self.assertIs(user.has_module_perms('Group'), False)
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')
user.user_permissions.add(perm)
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('auth.test'), True)
self.assertIs(user.has_perms(['auth.test2', 'auth.test3']), True)
@ -121,8 +130,8 @@ class BaseModelBackendTest:
group.permissions.add(perm)
user.groups.add(group)
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(), exp)
self.assertEqual(user.get_all_permissions(), {*expected_user_perms, 'auth.test_group'})
self.assertEqual(user.get_user_permissions(), expected_user_perms)
self.assertEqual(user.get_group_permissions(), {'auth.test_group'})
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.assertEqual(self.user.groups.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())
def test_str(self):