Django User Hierarchy

I have to create a web application that will implement something like a hierarchy of users. I would like to do this as follows: 1. The superuser makes users (with some permissions) who can also add users (only with the permissions that they own). These users can also add users, etc. No one will be able to edit users who have more permissions.

The thing is, I want to make the Django admin panel accessible to all these users. Is it possible to do this? I searched the Internet and did not find a solution. Thanks for the advice.

+4
source share
3 answers

You will need to create your own views to add users if you want to control the permissions of the created users. On the Django administration site, any user who can create users can create superusers.

From Django docs to user creation :

If you want your own account to be able to create users using the Django admin site, you need to give yourself permission to add users and change users (for example, Add User and Change User permissions). If your account has permission to add users but not change them, you cannot add users. What for? Because if you have permission to add users, you have the ability to create superusers, which in turn can change other users. Therefore, Django requires adding and changing permissions as a small security measure.

+2
source

Each user who needs access to the administrator must have the flag is_staff=True . It is never recommended that users who are not affiliated with your organization have access to an administrator. Seriously, just don't do it. If this is your plan, find another.

However, this can be done, but it is not for the faint of heart. There are so many. The first subclass is UserCreationForm and UserChangeForm by default (Auth uses two separate forms for it admin). Override the __init__ method for each of them to pull the request from kwargs (forms do not receive the request by default, but it is needed here, so you need to do a little workaround.) Then, by default subclass UserAdmin set form and add_form to new forms and override get_form (to go to request ) and each of the has_foo_permission methods to restrict access. The queryset method must also be overloaded, so users only see users that they can change in admin.

 from django.contrib.auth.admin import UserAdmin from django.contrib.auth.forms import UserCreationForm, UserChangeForm from django.contrib.auth.models import Group, Permission class CustomUserCreationForm(UserCreationForm): class Meta(UserCreationForm.Meta): pass def __init__(self, *args, **kwargs): self.request = kwargs.pop('request', None) super(CustomUserCreationForm, self).__init__(*args, **kwargs) # Limit groups and permissions to those that belong to current user if self.request and not self.request.user.is_superuser: self.fields['groups'].queryset = self.request.user.groups.all() self.fields['user_permissions'].queryset = self.request.user.user_permissions.all() class CustomUserChangeForm(UserChangeForm): class Meta(UserChangeForm.Meta): pass def __init__(self, *args, **kwargs): self.request = kwargs.pop('request', None) super(CustomUserChangeForm, self).__init__(*args, **kwargs) # Limit groups and permissions to those that belong to current user if self.request and not self.request.user.is_superuser: self.fields['groups'].queryset = self.request.user.groups.all() self.fields['user_permissions'].queryset = self.request.user.user_permissions.all() class CustomUserAdmin(UserAdmin): form = UserChangeForm add_form = UserCreationForm limited_fieldsets = ( # Copied from default `UserAdmin`, but removed `is_superuser` (None, {'fields': ('username', 'password')}), (_('Personal info'), {'fields': ('first_name', 'last_name', 'email')}), (_('Permissions'), {'fields': ('is_active', 'is_staff', 'user_permissions')}), (_('Important dates'), {'fields': ('last_login', 'date_joined')}), (_('Groups'), {'fields': ('groups',)}), ) def get_fieldsets(self, request, obj=None): if not obj: return self.add_fieldsets elif not request.user.is_superuser: return self.limited_fieldsets else: return super(CustomUserAdmin, self).get_fieldsets(request, obj) def get_form(self, request, obj=None, **kwargs): """Return a metaclass that will automatically pass `request` kwarg into the form""" ModelForm = super(LinkAdmin, self).get_form(request, obj, **kwargs) class ModelFormMetaClass(ModelForm): def __new__(cls, *args, **kwargs): kwargs['request'] = request return ModelForm(*args, **kwargs) return ModelFormMetaClass def has_add_permission(self, request): """ If not superuser only allow add if the current user has at least some groups or permissions. (they'll have to be able to at least have something to assign the user they are creating). """ if not request.user.is_superuser: if not request.user.groups.exists() or not request.user.user_permissions.exist(): return False return True def has_change_permission(self, request, obj=None): """ If not superuser, current user can only modify users who have a subset of the groups and permissions they have. """ if obj and not request.user.is_superuser: # Check that all of the object groups are in the current user groups user_groups = list(request.user.groups.all()) for group in obj.groups.all(): try: user_groups.index(group) except ValueError: return False # Check that all of the object permissions are in the current user permissions user_permissions = list(request.user.user_permissions.all()) for permission in obj.user_permissions.all(): try: user_permissions.index(permission) except ValueError: return False return True def has_delete_permission(self, request, obj=None): """Same logic as `has_change_permission`""" return self.has_change_permission(request, obj) def queryset(self, request): qs = super(CustomUserAdmin, self).queryset(self, request) if request.user.is_superuser: return qs else: """ This part is a little counter-intuitive. We're going to first get a list of all groups/permissions that don't belong to the user, and then use that to exclude users that do have those from the queryset. """ user_group_pks = [g.pk for g request.user.groups.values('pk')] exclude_groups = Group.objects.exclude(pk__in=user_group_pks) user_permission_pks = [p.pk for p in request.user.user_permissions.values('pk')] exclude_permissions = Permission.objects.exclude(pk__in=user_permission_pks) return qs.exclude(groups__in=exclude_groups, user_permissions__in=exclude_permissions) admin.site.unregister(User) admin.site.register(User, CustomUserAdmin) 
+2
source

Django contains an embedded system to support the User Hierarchy - Django-RBAC.

RBAC stands for Role Based Access Control . Its mechanism for creating and managing hierarchy-based permission. You just need to study this a bit.

+1
source

Source: https://habr.com/ru/post/1380775/


All Articles