【问题标题】:Add object level permission to generic view将对象级别权限添加到通用视图
【发布时间】:2012-05-06 19:16:32
【问题描述】:

情况很简单: 我正在编写一个多用户博客系统。系统应防止非所有者编辑或删除博客文章。在我看来,我使用通用视图。

类博客更新视图(更新视图): ...

我知道我应该使用@method_decorator 来装饰调度方法。但是,大多数示例只是 @method_decorator(login_required) 或模型级别权限。如何应用对象级别的权限来检查 request.user 是否是这篇博文的作者? 例如,我尝试使用 django-authority 应用程序,并且在此文件中有一个 BlogPermission 类。我试图在这个类中定义一个方法,例如

def blog_edit(self, ??, ??)

我应该在这个方法中添加什么?

然后这样调用: @method_decorator(permission_required('blog_permission.blog_edit(???)'))

我应该在这里传递什么?

更新:阅读method_decorator代码后,我发现它只能接受没有参数的函数。我认为这就是为什么 permission_required 在这里不起作用。但是解决这个问题的方法是什么?

更新解决方案:

在 dispatch 方法中,我检查用户权限,如果用户不满足权限,则返回 HttpResponseForbidden()。

【问题讨论】:

  • 您可以在get_object 方法中查看您的权限。使用 CBV 的装饰器看起来不太好。
  • 所以你的意思是没有简单的方法将对象级装饰器应用于基于类的通用视图? @ilvar
  • 我的意思是在get_object 中做起来会更容易。为了让它更干燥,你可以用 get_object 制作一个 Mixin 并使用它。
  • 嗨,ilvar,您能举个例子吗?比如我想写一个博客updateview,在get_object中如果我发现request.user不是blog.author,我应该返回什么来引发403错误?谢谢@Daniel Roseman

标签: django django-views django-permissions


【解决方案1】:

您可以使用基于类的视图来做到这一点:

class BlogEdit(UpdateView):
    model = Blog

    def dispatch(self, request, *args, **kwargs):
        if not request.user.has_perm('blog_permission.blog_edit'):
            return HttpResponseForbidden()
        return super(BlogEdit, self).dispatch(request, *args, **kwargs)

    # OR (for object-level perms)

    def get_object(self, *args, **kwargs):
        obj = super(BlogEdit, self).get_object(*args, **kwargs)
        if not obj.user == self.request.user:
            raise Http404 # maybe you'll need to write a middleware to catch 403's same way
        return obj

【讨论】:

  • 可以引发内置异常django.core.exceptions.PermissionDenied 以显示来自get_object 的403 错误页面。然后,您可以在403.html 模板中自定义错误,或者在 URLconf 中使用handler403 覆盖视图(请参阅docs.djangoproject.com/en/1.7/topics/http/views/…)。不幸的是,您无法通过异常传递消息,并且模板上下文未通过内置行为传递原始异常。如果要显示特殊消息,则需要创建中间件。
【解决方案2】:

另一种选择是使用UserPassesTestMixin(或user_passes_test,用于基于函数)。

class UserPassesTestMixin

使用基于类的视图时,您可以使用 UserPassesTestMixin 这样做。

test_func()

你必须重写类的 test_func() 方法来 提供执行的测试。此外,您可以设置任何 AccessMixin的参数自定义处理 未经授权的用户:

from django.contrib.auth.mixins import UserPassesTestMixin

class MyView(UserPassesTestMixin, View):

    def test_func(self):
        return self.request.user.email.endswith('@example.com')

我们现在可以检查是否允许self.request.user 处理传递给self.request.GET 或self.request.POST 的详细信息。

class MyView(UserPassesTestMixin, View):
    raise_exception = True  # To not redirect to the login url and just return 403. For the other settings, see https://docs.djangoproject.com/en/3.2/topics/auth/default/#django.contrib.auth.mixins.AccessMixin

    def test_func(self):
        return (
            self.request.user.is_staff
            or self.request.user.has_perm('app.change_blog')
            or self.request.user.email.endswith('@company.staff.com')
            or is_requested_object_accessible(self.request.user, self.request.GET, self.request.POST)  # If you have a custom checker
        )
    ...

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-01-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-12
    • 2015-06-21
    相关资源
    最近更新 更多