如何使非员工用户访问Django管理站点?

11
我希望能够实现第二个管理员站点,该站点提供主要管理员站点的一部分功能。这是可能的,并在Django文档中有描述。
然而,我想限制对主要管理员站点的访问。某些用户可以访问第二个站点,但不能访问主站点。
为了实现这个功能,我希望这些用户不属于员工(is_staff=False),并重写AdminSite.has_permission
class SecondaryAdminSite(AdminSite):
    
    def has_permission(self, request):
        if request.user.is_anonymous:
            try:
                username = request.POST['username']
                password = request.POST['password']
            except KeyError:
                return False
            try:
                user = User.objects.get(username = username)
                if user.check_password(password):
                    return user.has_perm('app.change_onlythistable')
                else:
                    return False
            except User.DoesNotExist:
                return False
        else:
            return request.user.has_perm('app.change_onlythistable')

很不幸,这种方法行不通。用户可以登录,但无法在辅助管理站点中看到任何内容。
这种方法有什么问题? 有没有想法如何实现此功能?
提前感谢。

为什么不将用户分成超级用户、经理、客户等,权限系统可以完美地工作。 - Tomasz Zieliński
@Tomasz:我也在做同样的事情。第二个管理站点有不同的目的,因此面向不同类型的用户。我希望避免他们连接到通常的管理员界面。 - luc
我假设您正在验证是否调用了正确的 has_permission 函数?页面上完全没有任何显示吗(即完全空白),还是只是隐藏了管理员功能? - Jordan Reiter
它说我没有此应用程序的权限。如果我恢复已登录用户的is_staff,则可以查看模型。 - luc
管理员需要 is_staff 来进行授权。如果你有某些理由不能将这些用户设置为真,我认为最好的选择是编写自己的管理员视图。通过像 has_permission 装饰器这样的访问控制,您可以强制执行自己的授权方案。 - Paul Bissex
3个回答

6

以下是针对 Django >= 3.2 的解决方案。

  • 创建一个AdminSite的子类。
  • 重写has_permission()方法,以删除is_staff检查。
  • 重写login_form,使用AuthenticationForm
    • AdminSite使用AdminAuthenticationForm,该表单扩展了AuthenticationForm 并添加了对is_staff的检查。

代码

# PROJECT/APP/admin.py

from django.contrib.admin import AdminSite
from django.contrib.admin.forms import AuthenticationForm


class MyAdminSite(AdminSite):
    """
    App-specific admin site implementation
    """

    login_form = AuthenticationForm

    site_header = 'Todomon'

    def has_permission(self, request):
        """
        Checks if the current user has access.
        """
        return request.user.is_active


site = MyAdminSite(name='myadmin')


完美运行 - mariofix

4

我认为现在您的方法应该是可行的:http://code.djangoproject.com/ticket/14434(5周前关闭)

但是,除了staff_member_required装饰器之外,明确的"is_staff"检查仍然在两个地方进行:

  • django.contrib.admin.forms.AdminAuthenticationForm.clean()

    除了"has_permission()"之外,您需要为非员工AdminSite提供一个不执行is_staff检查的"login_form",因此可以仅子类化并相应地调整clean()。

  • templates/admin/base.html

    需要稍微自定义。 具有id“user-tools”的div仅显示活动员工成员。 我假设这是因为登录表单也使用此模板,某人可能已经以活动的非员工成员身份登录,但仍然不应看到这些链接。


请告诉我你的进展,因为它还没有经过测试,我也想在某个阶段做同样的事情 :-) - Danny W. Adair
如果这是您需要更改的全部内容,请回复工单。为了获得额外的加分,您甚至可以在那里修补程序,让每个人都受益! :) - SmileyChris
我不认为我了解足够的AdminSite来创建一个补丁:-)...棘手,棘手-AdminSite.login_form是一个AdminAuthenticationForm,但后者还没有一个属性去另一个方向询问“它的”AdminSite(多个可以共享相同的login_form…)是否有has_permission()…那可以传递到构造函数中,但我不知道后果-与请求(cookies)一起实例化...模板也有同样的问题。逐个案例地,我可以用另一个硬编码的代码替换一个,通用解决方案更难... - Danny W. Adair

-1
这种方法有什么问题?有没有想法如何实现这个功能?
这种方法的问题在于,权限和组已经可以为您提供所需的内容。如果您只需要划分用户,则无需子类化AdminSite。
这可能就是为什么这个功能文档如此贫乏的原因,我个人认为。

1
第二个站点不仅是管理权限的另一种方式,还提供自定义屏幕和其他功能。Django管理站点非常好,并且可以高度定制化。但奇怪的是,它有点难以定制。 - luc

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接