可以合并 PermissionRequiredMixin 和 LoginRequiredMixin 吗?

Posted

技术标签:

【中文标题】可以合并 PermissionRequiredMixin 和 LoginRequiredMixin 吗?【英文标题】:Can PermissionRequiredMixin and LoginRequiredMixin be combined? 【发布时间】:2016-04-13 02:50:38 【问题描述】:

我有一些用户被允许查看某个视图。

为了允许用户登录并使用403 Forbidden 抱怨那些看不到该登录的用户,我可以使用以下内容(如here 所述):

@permission_required('polls.can_vote', raise_exception=True)
@login_required
def my_view(request):
    ...

这确实按预期工作。但我所有的观点都是基于类的观点。从 Django 1.9(终于!)开始,有很多漂亮的 mixin 可以做一些只能通过装饰器才能完成的事情。不过……

class MyClassView(LoginRequiredMixin, PermissionRequiredMixin, TemplateView):
    raise_exception = <???>
    permission_required = 'polls.can_vote'
    template_name = 'poll_vote.html'

这不起作用。因为LoginRequiredMixinPermissionRequiredMixin 都使用raise_exception 标志,所以我不能将其设置为任何值。

如果raise_exceptionTrue,则未登录的用户会收到403 Forbidden(我不想要)。 如果raise_exceptionFalse,则不允许查看视图的用户将被重定向到登录页面,由于用户已登录,该页面将再次重定向到这页纸。创建一个根本不是花哨的重定向循环。

当然,我可以实现自己的 mixin,其行为符合我的预期,但是在视图本身中是否有任何 Django 方式来执行此操作? (不在urls.py

【问题讨论】:

【参考方案1】:

在许多情况下,为未经身份验证的用户引发 403 是预期的行为。所以是的,你需要一个自定义的 mixin:

class LoggedInPermissionsMixin(PermissionRequiredMixin):
     def dispatch(self, request, *args, **kwargs):
        if not self.request.user.is_authenticated():
            return redirect_to_login(self.request.get_full_path(),
                                     self.get_login_url(), self.get_redirect_field_name())
        if not self.has_permission():
            # We could also use "return self.handle_no_permission()" here
            raise PermissionDenied(self.get_permission_denied_message())
        return super(LoggedInPermissionsMixin, self).dispatch(request, *args, **kwargs)

【讨论】:

【参考方案2】:

所需的行为是自 2.1 以来的默认行为,因此其他答案已过时:

在 2.1 中更改:在旧版本中,没有权限的经过身份验证的用户被重定向到登录页面(导致循环),而不是接收 HTTP 403 Forbidden 响应。 [src]

【讨论】:

这个问题被标记为 Django 1.9,因为它在当时看起来很相关。很高兴知道当前的行为,到目前为止:)【参考方案3】:

我想添加评论,但我的声誉不允许。下面的呢?我觉得下面的内容更具可读性?

cmets 后更新

我的理由是:您基本上是从LoginRequiredMixin 编写修改后的dispatch,然后设置raise_exception = TruePermissionRequiredMixinraise PermissionDenied 不满足正确的权限时

class LoggedInPermissionsMixin(PermissionRequiredMixin):
    raise_exception = True

    def dispatch(self, request, *args, **kwargs):
        if not self.request.user.is_authenticated():
            return redirect_to_login(self.request.get_full_path(),
                                     self.get_login_url(),
                                     self.get_redirect_field_name())
        return super(LoggedInPermissionsMixin, self).dispatch(request, *args, **kwargs)

【讨论】:

【参考方案4】:

最简单的解决方案似乎是自定义视图 mixin。 类似的东西:

class PermissionsMixin(PermissionRequiredMixin):
    def handle_no_permission(self):
        self.raise_exception = self.request.user.is_authenticated()
        return super(PermissionsMixin, self).handle_no_permission()

或者,像往常一样使用PermissionRequiredMixin 并将这个handle_no_premission 放到每个CBV。

【讨论】:

以上是关于可以合并 PermissionRequiredMixin 和 LoginRequiredMixin 吗?的主要内容,如果未能解决你的问题,请参考以下文章

7620:区间合并

python如何合并两个列表?

区间合并

C#DataGridView怎么合并单元格

PDF文档怎样在线合并?

ilmerge 可以将c++的dll合并吗