如何限制Django中管理员页面的访问?

17 投票
8 回答
18158 浏览
提问于 2025-04-18 12:01

我想让Django的管理界面在生产环境中只能让超级用户和工作人员访问,其他用户,包括未登录的用户都应该看到404错误页面。这样做可以吗?如果可以的话,怎么实现呢?

8 个回答

0

你可以自己创建一个叫做 admin_login_required 的装饰器。这个装饰器的作用是检查是否有用户登录,以及这个用户是否是管理员。如果没有用户登录,或者用户不是管理员,你可以把他们引导到登录页面,或者显示一条消息告诉他们没有权限。

这里有一个很好的例子,教你如何为 Django 的视图写一个装饰器。http://passingcuriosity.com/2009/writing-view-decorators-for-django/

这个页面介绍了一个叫做 anonymous_required 的装饰器示例,要求用户必须是匿名的。你可以参考这个例子,按照我上面提供的要求来实现一个 admin_login_required 的装饰器,或者自己想出其他的场景。

祝你好运。

1

我更新了@ip.的中间件版本。这个版本使用了process_view,可以直接检查某个视图是否属于管理后台,而不是仅仅检查网址是否在管理后台。它还会在未授权用户尝试访问管理后台时,添加一个警告日志记录,并简化了if的逻辑。这段代码是为Python 3和Django 2编写的。

from inspect import getmodule
import django.contrib.admin.sites
from django.http import Http404
import logging 

logger = logging.getLogger(__name__)


class RestrictStaffToAdminMiddleware:
    """
    A middleware that restricts staff members access to administration panels.
    """
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        response = self.get_response(request)
        return response

    def process_view(self, request, view_func, view_args, view_kwargs):
        module = getmodule(view_func)
        if (module is django.contrib.admin.sites) and (not request.user.is_staff):
            ip = request.META.get('HTTP_X_REAL_IP', request.META.get('REMOTE_ADDR'))
            ua = request.META.get('HTTP_USER_AGENT')
            logger.warn(f'Non-staff user "{request.user}" attempted to access admin site at "{request.get_full_path()}". UA = "{ua}", IP = "{ip}", Method = {request.method}')
            raise Http404

1

如果你在使用默认的Django后台页面,Django已经内置了一些控制措施来限制对这些页面的访问。用户模型中的 is_staff 这个布尔值决定了用户是否可以访问Django的后台页面。而 is_superuser 这个布尔值则决定了用户是否拥有所有权限,而不需要单独分配这些权限。不过要注意,is_superuser不会自动让用户访问Django后台页面;无论 is_superuser 的值是什么,用户必须将 is_staff 设置为True,才能访问Django的后台页面。

https://docs.djangoproject.com/en/1.6/ref/contrib/auth/#django.contrib.auth.models.User.is_staff

但是我不知道如果一个非工作人员用户尝试访问Django后台界面,Django是否会返回404错误。

6

在使用 AdminSite 类之前,先覆盖它的 admin_view 部分。

在 admin.py 文件中(如果没有这个文件就新建一个)添加:

from functools import update_wrapper

from django.http import Http404
from django.views.decorators.cache import never_cache
from django.views.decorators.csrf import csrf_protect


def admin_view(view, cacheable=False):
    """
    Overwrite the default admin view to return 404 for not logged in users.
    """
    def inner(request, *args, **kwargs):
        if not request.user.is_active and not request.user.is_staff:
            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)

然后在你的 urls 文件中添加:

from django.conf.urls import patterns, include, url
from django.contrib import admin
from django.views.defaults import page_not_found

from my_project.admin import admin_view
admin.site.admin_view = admin_view

urlpatterns = patterns('',
    url(r'^admin/login/', page_not_found),
    url(r'^admin/', include(admin.site.urls)),
)

当然,如果你还想让登录页面可以找到,就把 url(r'^admin/login/', page_not_found) 这一行去掉。

22

我最后写了一个中间件来解决这个问题:

from django.core.urlresolvers import reverse
from django.http import Http404

class RestrictStaffToAdminMiddleware(object):
    """
    A middleware that restricts staff members access to administration panels.
    """
    def process_request(self, request):
        if request.path.startswith(reverse('admin:index')):
            if request.user.is_authenticated():
                if not request.user.is_staff:
                    raise Http404
            else:
                raise Http404

撰写回答