我正在向我们的网站添加服务条款接受要求,并试图找出在Django's authentication框架内处理此问题的最佳方法。
为简单起见,这里是UserProfile
模型:
class UserProfile(models.Model):
user = models.OneToOneField(User)
accepted_tos_at = models.DateTimeField(default=None, editable=False, null=True)
基本上我想要做的是检查accepted_tos_at
是不是None
(或实际上大于上次TOS修订的日期)。如果它通过了此测试,那么我们会正常进行身份验证,但如果是None
,则除了login
和tos_display
之外的所有视图都无法访问。
我所依赖的是你应该如何在全球范围内做这件事?我宁愿不在我的每个观点中添加user_passes_test
装饰器,同样我也希望避免在我的每个观点中测试此权限。必须有一个更清洁的方式。
答案 0 :(得分:8)
通常,当您谈论应该适用于每个视图的内容时,您谈论的是中间件。在您的情况下,这是相对简单的:
class AcceptTOSMiddleware(object):
def process_request(request):
login_url = reverse('login')
tos_url = reverse('tos_display')
if request.path not in [login_url, tos_url]:
profile = request.user.get_profile()
if profile.accepted_tos_at is None or \
profile.accepted_tos_at < settings.LAST_TOS_REVISION:
return HttpResponseRedirect(tos_url)
return None
首先,检查请求的URL是否不是登录或TOS视图。如果需要重定向,这可以防止无限循环。然后,检查accepted_tos_at
。我假设您只是将最后修订日期存储为设置,因此如果您有其他计划,则需要修改它。如果需要接受TOS,则用户被重定向到TOS视图,否则,中间件返回None
,告诉Django继续正常处理请求。
只需将中间件添加到MIDDLEWARE_CLASSES
,您就是黄金。
答案 1 :(得分:1)
我最近使用基于类的视图和mixins进行了身份验证。请查看django-braces中的LoginRequiredMixin
作为示例。
这确实意味着你所有的观点(你想要保护的)需要包含一个共同的混合,但这是我所知道的最干净的方式。
用法(来自docs)是这样的:
from django.views.generic import TemplateView
from braces.views import LoginRequiredMixin
class SomeSecretView(LoginRequiredMixin, TemplateView):
template_name = "path/to/template.html"
def get(self, request):
return self.render_to_response({})
您可能想要定义自己的mixin,它可能看起来像这样(未经测试):
class AcceptedTOSRequiredMixin(object):
def dispatch(self, request, *args, **kwargs):
profile = request.user.get_profile()
if not profile or profile.accepted_tos_at is None:
return HttpResponseForbidden() # return a forbidden response.
return super(AcceptedTOSRequiredMixin, self).dispatch(request,
*args, **kwargs)
其他方法包括在URL级别对它们进行装饰,但在我看来这是更加丑陋的(我很乐意挖掘出一个例子,看看它有什么帮助)。