I'm currently learning my way around the permission framework in Django and I'm looking to define a set of permissions to a user, which defines if they can see or modify other users in the system.
I'm using the django.auth
framework on a multi-schema database where each schema has its own set of users.
I want to essentially apply this, but to the built-in users model
.
class Meta:
permissions = (
("can_view_users", "Can view all users"),
("can_modify_users", "Can modify all users"),
("can_password_reset_users", "Can reset passwords for all users"),
("can_delete_users", "Can delete all users"),
)
However I cannot seem to find any documentation on applying this logic to the built-in authentication framework.
I have resolved this by deploying my own permission app
. I still create and manage users & sessions via the built-in frameworks however utilize my own model
for managing user permissions.
It works as I intended and lets me customize as much as I would like from a per user perspective.
Steps
users
Permissions
with ForeignKey
to AUTH_USER_MODEL
At this point, pages cannot be utilize if the user does not have the specified permission. This is great as if the user tried to post
to users/new
they server will respond with HTTP 503
.
The next problem was modifying the base template so users would only see the menu options they were permitted to see. I achieved this by using a custom context_processor
.
context_processor
which utilizes Permissions
user_has_perms
to retrieve all permissions for the authenticated user.settings.py
djangos
template processing to render fields user has access toCode
model
Permissions
class Permissions(models.Model):
permission_id = models.AutoField(primary_key=True)
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
## User Management ##
can_user_view_staff = models.BooleanField(default = False)
def user_has_perms(user, perm):
user_exists = Permissions.objects.filter(user_id=user).count()
if user_exists:
if perm == None:
## if no permission specified, return all permissions for user ##
return Permissions.objects.filter(user_id=user)
else:
return Permissions.objects.filter(user_id=user).values(perm).last()[perm]
else:
return False
decorator
authorization
from django.http import HttpResponseForbidden
from apps.users.models import user_has_perms
## Check if user has permission to load page ##
def authorization_required(permissions=''):
def decorator(view):
def wrapper(request, *args, **kwargs):
can_user = user_has_perms(request.user, permissions)
if can_user or request.user.is_superuser:
return view(request, *args, **kwargs)
else:
return HttpResponseForbidden()
return wrapper
return decorator
views
view with decorator
from decorators.authorization import authorization_required
@login_required
@authorization_required('can_user_view_staff')
def users(request):
user_model = get_user_model()
user_list = user_model.objects.all()
context = {
'users': user_list
}
return render(request, 'users/users.html', context)
context_processor
from apps.users.models import user_has_perms
def permissions(request):
if request.user.is_authenticated:
user_perms = user_has_perms(request.user, None)
else:
user_perms = None
return {
'user_perms': user_perms
}
Modify settings.py
to add new processor
TEMPLATES = [
{
'OPTIONS': {
'context_processors': [
'context_processors.perm_context.permissions',
],
},
},
]
Update base.html to check user permissions before rendering fields
{% if user_perms.can_user_view_staff or request.user.is_superuser %}
<a class="dropdown-item" href="/users">User Management</a>
{% endif %}