Restricting whole django app to the normal users

Viewed 1277

I am not using django built-in admin panel for the admin page but I am trying to add functionality like django-admin.I want to restrict normal users to the admin app and for this I check like this if not request.user.is_superuser in every function where I want to restrict.It does the job pretty well but in the app there can be so many functions and i have to check this in every function inside the app and I think this should not be the good solution.So is there any solution so that I can give access the whole admin functionality to only superuser without checking user with if not request.user.is_superuser in every function inside the admin app ?

views.py

    def a(request):
    if not request.user.is_superuser:
        return redirect('login')
     ..........
    
    def b(request):
    if not request.user.is_superuser:
        return redirect('login')
    .............
    
    def c(request):
    if not request.user.is_superuser:
        return redirect('login')
    ...........
  
    def d(request):
    if not request.user.is_superuser:
        return redirect('login')
    ....
3 Answers

custom decorator

decorators.py

from django.contrib.auth import REDIRECT_FIELD_NAME
from django.contrib.auth.decorators import user_passes_test


def superuser_only(view_func=None, redirect_field_name=REDIRECT_FIELD_NAME,
                          login_url='login'):
    """
    Decorator for views that checks that the user is logged in and is a staff
    member, redirecting to the login page if necessary.
    """
    actual_decorator = user_passes_test(
        lambda u: u.is_active and u.is_superuser,
        login_url=login_url,
        redirect_field_name=redirect_field_name
    )
    if view_func:
        return actual_decorator(view_func)
    return actual_decorator

To apply decorator to all of your urls

urls.py

def dec_patterns(patterns):
    decorated_patterns = []
    for pattern in patterns:
        callback = pattern.callback
        pattern.callback = superuser_only(callback)
        pattern._callback = superuser_only(callback)
        decorated_patterns.append(pattern)
    return decorated_patterns

url_patterns = [
    path("my-path/", views.my_view),
]
url_patterns = dec_patterns(url_patterns)

You can write a custom middleware to achieve this.

from django.urls import reverse
from django.shortcuts import redirect


class RestrictUserMiddleware(object):
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        if request.path.find("/admin/") > -1:  # restricted admin url for custom admin site
           if not request.user.is_superuser:
              return redirect(reverse('login_url_name'))
        response = self.get_response(request)
        return response

And use that middleware in SETTINGS file:

MIDDLEWARE = [
    # Other middlewares
    'path.to.RestrictUserMiddleware',
]

You can use user_passes_test() decorator with a lambda function.

from django.contrib.auth.decorators import user_passes_test
from django.http import JsonResponse

# first solution

@user_passes_test(lambda user: user.is_superuser)
def test_func(request):
    return JsonResponse(data={})

# second solution

def check_user(user):
    # you can do more actions here
    return user.is_superuser

@user_passes_test(check_user)
def test_func(request):
    return JsonResponse(data={})

According to your question, simply you can add this @user_passes_test(lambda user: user.is_superuser) line which is the first solution of my answer on top of your functions or can go to second solution if you need to do more things.

Related