pythondjangowebbackend

How to create middleware to check user's permissions in django?


I'm trying to create custom adminpanel in django. I can create users there, and I can check wheter the user is_admin or not. If the user is not admin, he shouldn't be able to visit adminpanel page, and shouldn't be able to modify anything.

I need to create middleware to check whether user is admin or not, and if not, redirect him to the home page. I think I should use @permission_required, but I'm not sure how to use it in middleware.

This is a function to create new user:

# views.py
def createNewUser(request):
    if request.method == 'POST':
        user = User.objects.create(username=request.POST.get('username'),
                                   email=request.POST.get('email'),
                                   password=request.POST.get('password'))
        if request.POST.get('is_admin') == 'True':
            is_admin = 'True'
        else:
            is_admin = 'False'
            user.user_permissions.clear()
        user.save()
        useraccount = UserAccount.objects.create(user=user, is_admin=is_admin)
        useraccount.save()
        return redirect('users')
    return render(request, 'adminpanel/create_user.html', {})

This user can be admin. If I don't check a checkbox, he is not admin and he's not allowed to do anything on this page. I just clear all permissions.(I know that it might be better to remove specific permissions, rather than all, but this is just an example) Now I have to check his permissions before every function:

@permission_required('poll.view_category', login_url='home')
def home(request):
    return render(request, 'adminpanel/main.html', {})

So, how to use this decorator in middleware? (It should only be called in adminpanel requests) And is it better to use function or class-based middleware? What is the difference?


Solution

  • Middleware checks every request, so probably isn't the most efficient way to limit access to a single view, or even a few views. Using decorators might be a better bet.

    The simplest way to do this is simply to check at the top of your view

    def home(request):
        if not request.user.useraccount.is_admin
            return render(request, 'login.html', {})
    

    If you want to re-use this logic for multiple views, you can use the user_passes_test decorator

    from django.contrib.auth.decorators import user_passes_test
    
    
    def admin_check(user):
        return user.useraccount.is_admin
    
    
    @user_passes_test(admin_check)
    def my_view(request):
    
    

    If you want to use that in multiple apps without recreating the test you can use a lambda function

    @user_passes_test(lambda u: u.useraccount.is_admin)
    

    My personal preference is to understand function based views before class-based ones so you know what class based views are doing for you behind the scenes. As you're using function based in the above, I'd stick with them for the moment.