Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to restrict non staff users from accessing django-admin

My django-admin page is located at

http://127.0.0.1:8000/admin/

Suppose there are 3 users in my website.

  1. Superuser
  2. Staff
  3. End user

If anyone of these three users tries to access this link http://127.0.0.1:8000/admin/, 1st and 2nd can access it. And End User is not able to access it. Till this, it is fine.

What I want is to do is to show Error 404 to End User. He/She should never know that this link is for admin page. Moreover, if anyone is not logged in, they should also see same 404 Page.

I have referred this link but it takes me to another default page.

PFA for the same


enter image description here


PS: I am using Signin With Google, so it should not redirect me there.

I am trying this since 3 continous days, so any help is highly appreciated. Thanks in advance.

Django-Version: 3. 0. 5

like image 714
ajinzrathod Avatar asked Oct 18 '25 02:10

ajinzrathod


1 Answers

You first need to make a custom decorator that would give a 404 if the user is not a staff:

from django.http import Http404
from functools import wraps

def staff_required(func):
    @wraps(func)
    def wrapper(request, *args, **kwargs):
        if request.user.is_staff:
            return func(request, *args, **kwargs)
        raise Http404()
    return wrapper

Next we will use this decorator as described in your linked question,:

from django.contrib import admin

admin.site.login = staff_required(admin.site.login)

urlpatterns = [
    path('admin/', admin.site.urls),
]

Edit: Above method was a bit hacky it would show the login pages url to the user even if it gives a 404 error. It would be better to make a custom admin site class and use it. The admin site has a method admin_view which decorates the admin views which we shall override. We shall do this in the file admin.py in the projects main app (let's say the project is named myproject)

from functools import update_wrapper

from django.contrib import admin
from django.http import (
    Http404, HttpResponseRedirect,
)
from django.urls import reverse
from django.views.decorators.cache import never_cache
from django.views.decorators.csrf import csrf_protect


class MyAdminSite(admin.AdminSite):
    def admin_view(self, view, cacheable=False):
        def inner(request, *args, **kwargs):
            if not self.has_permission(request):
                if request.path == reverse('admin:logout', current_app=self.name):
                    index_path = reverse('admin:index', current_app=self.name)
                    return HttpResponseRedirect(index_path)
                raise Http404()
            return view(request, *args, **kwargs)
        if not cacheable:
            inner = never_cache(inner)
        # We add csrf_protect here so this function can be used as a utility
        # function for any view, without having to repeat 'csrf_protect'.
        if not getattr(view, 'csrf_exempt', False):
            inner = csrf_protect(inner)
        return update_wrapper(inner, view)

Now we need to replace the default admin site with our custom admin site. To do this we will follow Overriding the default admin site [Django docs]:

In the projects main app's apps.py file (assuming project to be named myproject):

from django.contrib.admin.apps import AdminConfig

class MyAdminConfig(AdminConfig):
    default_site = 'myproject.admin.MyAdminSite'

Now in settings.py we will replace 'django.contrib.admin' with our own config class:

INSTALLED_APPS = [
    ...
    'myproject.apps.MyAdminConfig',  # replaces 'django.contrib.admin'
    ...
]
like image 95
Abdul Aziz Barkat Avatar answered Oct 20 '25 18:10

Abdul Aziz Barkat



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!