扩展django身份验证/授权的最佳方式

时间:2012-09-04 20:30:51

标签: django authentication

我正在向我们的网站添加服务条款接受要求,并试图找出在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,则除了logintos_display之外的所有视图都无法访问。

我所依赖的是你应该如何在全球范围内做这件事?我宁愿不在我的每个观点中添加user_passes_test装饰器,同样我也希望避免在我的每个观点中测试此权限。必须有一个更清洁的方式。

2 个答案:

答案 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级别对它们进行装饰,但在我看来这是更加丑陋的(我很乐意挖掘出一个例子,看看它有什么帮助)。