I'm having trouble understanding how to set permissions in Django. I want to have certain users who have the ability to view and modify a certain model that ordinary users cannot.
But after I assign permissions to a group, I cannot see the permissions assinged to the individual users in that group.
For example, in the shell:
from django.contrib.auth.models import Group, User, Permission
from django.contrib.contenttypes.models import ContentType
somemodel_ct = ContentType.objects.get(app_label='myappname', model='moderation')
can_view = Permission(name='Can View', codename='can_view_something',
content_type=somemodel_ct)
can_view.save()
can_modify = Permission(name='Can Modify', codename='can_modify_something',
content_type=somemodel_ct)
can_modify.save()
g = Group.objects.get(pk=1) # the group of moderators
g.permissions = [can_view, can_modify]
g.user_set.all() # can see alice and bob, alice is the superuser created after syncdb
alice.has_perm('can_view_something') # returns True
bob.has_perm('can_view_something') # returns False
Why aren't the permissions getting assigned to bob?
According to the documentation, permission should be in the format of <app label>.<permission codename>.
Returns True if the user has the specified permission, where perm is
in the format "< app label>.< permission codename>". (see documentation
on permissions). If the user is inactive, this method will always
return False.
Replace the following lines:
alice.has_perm('can_view_something')
bob.has_perm('can_view_something')
with:
alice.has_perm('myappname.can_view_something')
bob.has_perm('myappname.can_view_something')
And make sure that bob is an active user.
Why alive.has_perm(...) returned True
Django does not check permissions for active superuser. has_perm always return True for active superusers.
Relevant code:
def has_perm(self, perm, obj=None):
...
# Active superusers have all permissions.
if self.is_active and self.is_superuser:
return True
Related
I'm working on the permissions on a Django 4.1 application. All these permissions are given by groups. First permission first problem:
Permission codename: can_see_all_images
appname for the permission: dating
group having this permission: X-Gold
As you can see on the screenshot it seems that all the informations are correct:
First line: User is in the group
Second line, the group has the permission
Third line: The permission has the good codename
but line4: the user doesn't have the perm.
I restarted the server disconnected the user and reconnected it, nothing changed.
Note that if I give the permission directly to the user, it doesn't work. So I guess the problem does not come from the group.
Any idea?
Here is how the permission is created in the model:
permissions = [('can_see_all_images', _('Can see all images'))]
edit: my view code:
#login_required
def public_images(request, slug):
visited = get_object_or_404(User, slug=slug, is_active=True)
user = User.objects.get(id=request.user.id)
if user.has_perm('dating.can_see_all_images'):
print('ok')
else:
print('KO')
return render(request, 'dating/public_images.html', locals())
Thanks in advance
I found the problem, so I post it here in case someone meet the same.
I am using a custom authentication backend. This backend inherits from BasicBackend. In this case you have to redefine the has_perm() method because in the BaseBackend the original method return an empty tuple.
If you don't want to redefine it you need to inherit from ModelBackend and not BaseBackend.
This seems pretty trivial but I can't figure out what I'm doing wrong. I've checked several SO posts that sounded similar but the issue apparently lies elsewhere.
I have a custom permission on my model, can_key, and this is registered properly. When I try to add this permission to a newly created user, it's not added.
from django.contrib.auth import get_user_model
from django.contrib.auth.models import Permission
def create_dummy_user(self, username):
username = 'dummy_user'
user = get_user_model().objects.create(username=username, password='asdf4321')
user.save()
user = get_user_model().objects.get(username=username)
permission = Permission.objects.get(codename="can_key")
print(permission)
user.user_permissions.add(permission)
user = get_user_model().objects.get(username=username)
print(f"{user.username} is_active - {user.is_active}")
print(f"{user.username} has perm {permission.codename} - {user.has_perm(permission)}")
return user
This is the print outputs
test_web | main_app | record case | Can key record case
test_web | dummy_user is_active - True
test_web | dummy_user has perm can_key - False
So the user was created and the permission exists / is retrieved, but the permission isn't being added. Why?
You should change the parameter of has_perm() function with string. It's format is "app_name.codename". So you change the code like below
...
print(f"{user.username} has perm {permission.codename} - {user.has_perm('main_app.can_key')}")
...
You should review Django's permission caching documentation.
click to answer of your question
I want to do a API with django-graphene, but i want to apply the django default group permission when i user make a request this will have permission if his user-group allow him to CRUD.
Thanks.
This may not be an elegant solution, but it's one that works for mutations:
In my mutation, I have a custom function that returns true if the user pulled from info.context.user is in a group, or false if they are not:
class RelayCreateConversation(relay.ClientIDMutation):
# Set a variable as the field we want to use
conversation = graphene.Field(ConversationNode)
# Create a custom response as a string if the user doesn't have authentication
custom_response = graphene.String()
# What is passed through in the mutation
class Input:
participant_number = graphene.String()
def mutate_and_get_payload(root, info, **input):
submitted_by = info.context.user
# How I manage authentication
if not group_required(submitted_by, "send_and_receive_texts"):
custom_response = "You do not have the correct permissions to do this action"
return RelayCreateConversation(conversation=custom_response)
# mutation code here
And then I have a helper function which I import which is dead simple:
def group_required(user, *group_names):
if bool(user.groups.filter(name__in=group_names)) | user.is_superuser:
return True
return False
Limitations: I currently haven't tried to manage queries with this yet, just functions. If someone gets to that before I do, please comment or update my response.
I need to allow administrators to manage permissions for models on my site. Groups, Users, and Permissions are doing a great job of this right now. However, I also need to allow the administrators to manage the permissions of non-authenticated users - Anonymous Users. The docs say that anonymous user's group is always empty, so how can I allow administration of their permissions?
It is strange to add permissions to anonymous users. Docs say:
Django's permission framework does not have a place to store
permissions for anonymous users. However, it has a foundation that
allows custom authentication backends to specify authorization for
anonymous users. This is especially useful for the authors of
re-usable apps, who can delegate all questions of authorization to the
auth backend, rather than needing settings, for example, to control
anonymous access.
So you can set permissions to anon yuser, but with custom auth backend.
It is sometimes better to use declarative permission check, using decorators on the views with the needed permissions, like:
#permission_required('somemodel.can_add')
def add_model(request):
or leave it unrestricted for everyone(incl. anonymous user). Or some custom permission check..
Or if you want to have permissions anyway, you can always create a dummy user, let's say "AnonUser", to give it permissions, and then checking permissions to have something like:
if not user.is_authenticated():
dummy_user = User.objects.get(name="AnonUser")
if dummy_user.has_perm("somepermission"):
# bla bla bla
but this is something I'd never use..
I've gone with a custom backend to provide an anonymous group (as #Tisho suggests), which can easily be edited from the admin interface. Add the following class to AUTHENTICATION_BACKENDS in settings.py (e.g. 'appname.auth_backend.AnonymousPermissions').
Note that it's common to require a login before checking permissions (e.g. with login_required), which will have to be replaced with permission only checks.
from django.contrib.auth.models import Group
class AnonymousPermissions(object):
def get_anonymous_permissions(self):
#largely from django.contrib.auth.backends
group, group_created = Group.objects.get_or_create(name='Anonymous')
perms = group.permissions.all()
perms = perms.values_list('content_type__app_label', 'codename').order_by()
perms = set("%s.%s" % (ct, name) for ct, name in perms)
return perms
def get_group_permissions(self, user_obj, obj=None):
if user_obj.is_anonymous:
perm_cache_name = '_anonymous_perm_cache'
if not hasattr(user_obj, perm_cache_name):
setattr(user_obj, perm_cache_name, self.get_anonymous_permissions())
return getattr(user_obj, perm_cache_name)
return set()
def get_all_permissions(self, user_obj, obj=None):
return self.get_group_permissions(user_obj, obj)
def has_perm(self, user_obj, perm, obj=None):
return perm in self.get_group_permissions(user_obj, obj)
I've finally decided to make some tests for my apps but I'm stuck on testing if a user can change another user (depends on the type of the user -- I use django-rules to be able to do logical permission checks, but this is not important)
Here's the code I have so far
class RulesAndPermissionsTests(TestCase):
fixtures = ['auth_no_permissions.json', 'profiles.json', 'rules.json']
def setUp(self):
self.c = Client()
self.user = User.objects.get(username="estagiario")
self.non_staff = User.objects.get(username="fisica")
self.admin = User.objects.get(username="admin")
login = self.c.login(username='estagiario', password='estagiario')
def test_can_change_non_staff_users(self):
self.assertFalse(self.user.has_perm('logical_change_user', self.non_staff.profile)) # can't change non staff users without permission
# now add the permission and test it again
self.user.user_permissions.add(Permission.objects.get(codename='change_user'))
print self.user.get_all_permissions() # prints set([])
self.assertTrue(self.user.has_perm('logical_change_user', self.non_staff.profile))
Even after adding the permission, my user still has no permissions. Is this because I'm not allowed to create anything during the tests (is this a bad practice?)? Or does django cache the permissions somehow? If I add the permission at setUp it works, but I wanted to change it during the same test (testing with and without the permission).
Thanks in advance!
If you look at the source code for the ModelBackend, you can see that Django does cache the permissions on the user object.
You could try wiping the cache, but that could break your tests if the caching mechanism changes in future. The easiest thing to do is to refetch the user from the database in your test.
from django.contrib.auth.models import Permission
def test_can_change_non_staff_users(self):
self.assertFalse(self.user.has_perm('logical_change_user', self.non_staff.profile)) # can't change non staff users without permission
# now add the permission and test it again
self.user.user_permissions.add(Permission.objects.get(codename='change_user'))
# refetch user from the database
self.user = User.objects.get(pk=self.user.pk)
print self.user.get_all_permissions() # should now include new permission
self.assertTrue(self.user.has_perm('logical_change_user', self.non_staff.profile))