限制整个Django应用程序只对普通用户开放

3

我没有使用Django内置的管理面板作为管理员页面,但我正在尝试添加像django-admin一样的功能。我想要限制普通用户访问管理员应用程序,为此我在每个想要进行限制的函数中检查是否是超级用户,如 if not request.user.is_superuser 。它很有效果,但在应用程序中可能有很多函数,我必须在应用程序中的每个函数中都进行检查,我认为这不是一个好的解决方案。所以是否有任何解决方案,可以只给超级用户访问整个管理员功能,而无需在管理员应用程序中的每个函数中检查用户是否是超级用户?

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个回答

2

自定义装饰器

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

装饰器应用于您所有的网址

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)

我之前已经通过在每个函数中添加来实现限制整个应用程序功能的要求。 - arjun
@userme 使用“中间件”将会影响项目中的所有应用程序。它将检查每个请求,因此会稍微减慢应用程序的速度。 - anjaneyulubatta505
重写user_passes_test功能。代码可以在Django的GitHub存储库中找到。 - anjaneyulubatta505
我在哪里可以找到关于django.urls.path对象的文档? - Mas Zero
@MasZero https://docs.djangoproject.com/zh-hans/3.1/ref/urls/#path - anjaneyulubatta505

1
你可以编写自定义中间件来实现这一功能。
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

在SETTINGS文件中使用那个中间件:

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

你正在使用哪个版本的Django? - ruddra
@userme 是的,我找到了那个bug。我更新了我的答案,请再试一次。 - ruddra
@userme 我刚刚重新阅读了你的问题,但我并不完全清楚你所面临的问题。从逻辑上讲,“如果用户和用户是超级用户:登陆(请求,用户)”是正确的,因为你想限制Django应用程序中的用户,只允许超级用户登录。 - ruddra
如果您正在使用Django管理界面,则已经存在。如果您有自定义的管理界面,那么我会尽快更新答案。 - ruddra
1
@userme 请查看文档:https://docs.python.org/3/library/stdtypes.html#str.find。同时,您也可以查看这个反向文档:https://docs.djangoproject.com/en/2.2/ref/urlresolvers/#reverse。 - ruddra
显示剩余5条评论

0

您可以使用user_passes_test()装饰器与lambda函数一起使用。

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={})

根据您的问题,简单来说,您可以在您的函数顶部添加我的答案中的第一种解决方案,即@user_passes_test(lambda user: user.is_superuser)行,或者如果您需要执行更多操作,则可以选择第二种解决方案。

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