0

我创建了一个中间件,它允许我使用字典列表为我的任何视图指定一些访问规则。这些字典中的每一个都如下所示:

REQUIREMENTS=(
    {'viewname':'addtag',
     'permissions':'can_add_tags'},
    {'regex':re.compile(r'^somestart'),
    'user_check':lambda request:request.user.username=='sam'}
)

然后,在我的中间件中,我尝试找出哪些要求与当前请求匹配。为此,我过滤了完整的 REQUIREMENTS,并在过滤器函数中使用此代码检查路径是否匹配:

def process_request(self,request):

    def path_matches(self,req):
        path_matches = False

        if  (req.has_key('url') and req['url'] == request.path ) or\
            (req.has_key('regex') and req['regex'].search(request.path)) or\
            (req.has_key('viewname') and resolve(request.path).url_name==req['viewname']):
            path_matches=True

        return path_matches

    requirements = filter(path_matches,REQUIREMENTS)
    # now use the returned requirements to determine if a user
    # matches the requirement and

我现在的问题是:我应该按什么顺序使用支票?很明显,对 url 的检查是最快的,所以这必须是第一个。但接下来的问题是,是否应该首先遵循正则表达式搜索或 django 的 url 解析功能。

由于我现在没有任何性能问题,这更像是一个学术问题。如果有人有更好的解决方案来解决这个问题,那就更好了。


编辑:

为了对给定的答案做出反应:我想做的是创造一种可能性,将多个外部应用程序的视图限制在一个文件中。所以装饰器不是一种选择,只要我不想做这样的事情:

from ext_app1 import view1,view2
from ext_app2 import view3

@permission_required('can_do_stuff')
def view1_ext(*args,**kwargs):
    return view1(args,kwargs)

这将导致每次我更改权限时都重写 url 规范。我想避免这种情况。此外,我的解决方案允许 user_check 函数对用户进行检查,如下所示:

def check_user(user):
    if len(Item.objects.get(creator=user,datetime=today)) > 3:
        return False
    return True

这将是一种简单的方法,即限制用户每天可以上传多少项目。(好的,这也可以使用 user_passes_test )。

另一件事是,有时我只想在请求是 POST 或请求包含某个键:值对时才检查权限(比如'action':'delete'应该需要权限,而'action':'change'任何人都应该允许)。这也可以使用自定义装饰器来完成,但是一旦我需要新的检查,我就需要一个新的装饰器。

4

2 回答 2

1

如果您使用 Django 的内置用户身份验证和权限系统( django.contrib.auth),那么您应该考虑使用它提供的视图装饰器而不是中间件。这些为您提供了几个优势:

  • 一起更改的代码在同一个地方,也就是说,与更改其他权限相比,更改视图代码时更可能需要更改特定视图的权限。
  • 您不必自己编写大量代码,这使您的项目更小且更易于维护。

对于简单的情况,您可以使用login_requiredandpermission_required装饰器,对于更复杂的条件,user_passes_test装饰器允许您检查用户是否通过了您想要指定的任何条件。

对于视图函数,代码看起来像这样(示例来自文档):

from django.contrib.auth.decorators import permission_required

@permission_required('polls.can_vote')
def my_view(request):
    ...

如果您使用的是基于类的视图,那么它看起来会有些不同(同样,此示例取自文档):

from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
from django.views.generic import TemplateView

class ProtectedView(TemplateView):
    template_name = 'secret.html'

    @method_decorator(login_required)
    def dispatch(self, *args, **kwargs):
        return super(ProtectedView, self).dispatch(*args, **kwargs)

如果你有充分的理由不使用 Django 的权限系统,那么你仍然可以采用类似的方法。装饰器代码django.contrib.auth可以很容易地用作您自己的装饰器的基础。

于 2012-05-24T19:08:20.060 回答
1

您可能正在寻找user_passes_test 装饰器

您可以装饰您需要的视图,而不是使用中间件。

代码将如下所示:

from django.contrib.auth.decorators import user_passes_test

@user_passes_test(lambda user: user.has_perm('model.can_add_tags') \
                                and user.username == 'sam')
def my_view(request):
    ...  
于 2012-05-24T18:46:25.800 回答