可以合并 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'
这不起作用。因为LoginRequiredMixin
和PermissionRequiredMixin
都使用raise_exception
标志,所以我不能将其设置为任何值。
raise_exception
是True
,则未登录的用户会收到403 Forbidden
(我不想要)。
如果raise_exception
是False
,则不允许查看视图的用户将被重定向到登录页面,由于用户已登录,该页面将再次重定向到这页纸。创建一个根本不是花哨的重定向循环。
当然,我可以实现自己的 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 = True
。 PermissionRequiredMixin
将 raise 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 吗?的主要内容,如果未能解决你的问题,请参考以下文章