使Django的login_required成为默认的最佳方式 [英] Best way to make Django's login_required the default

查看:118
本文介绍了使Django的login_required成为默认的最佳方式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发一个大型的Django应用程序,绝大多数应用程序需要登录才能访问。这意味着我们所有的应用程序都已经洒掉了:

I'm working on a large Django app, the vast majority of which requires a login to access. This means that all throughout our app we've sprinkled:

@login_required
def view(...):

没关系,只要我们记得在任何地方添加, EM>!可悲的是,有时候我们忘记了,失败往往并不是很明显。如果唯一的视图链接在@login_required页面上,那么您不太可能会注意到您可以在没有登录的情况下实际访问该视图。但坏人可能会注意到这是一个问题。

That's fine, and it works great as long as we remember to add it everywhere! Sadly sometimes we forget, and the failure often isn't terribly evident. If the only link to a view is on a @login_required page then you're not likely to notice that you can actually reach that view without logging in. But the bad guys might notice, which is a problem.

我的想法是扭转系统。而不是必须在任何地方键入@login_required,而是我会有以下的东西:

My idea was to reverse the system. Instead of having to type @login_required everywhere, instead I'd have something like:

@public
def public_view(...):

只是为了公共的东西。我试图用一些中间件实现这一点,我似乎无法让它工作。我所尝试的一切都与我们正在使用的其他中间件进行了很好的互动。接下来,我尝试写一些东西来遍历URL模式,以检查所有不是@public的内容都被标记为@login_required - 至少如果我们忘记了某些东西,我们会收到一个快速错误。但是,我不知道如何判断@login_required是否被应用于视图...

Just for the public stuff. I tried to implement this with some middleware and I couldn't seem to get it to work. Everything I tried interacted badly with other middleware we're using, I think. Next up I tried writing something to traverse the URL patterns to check that everything that's not @public was marked @login_required - at least then we'd get a quick error if we forgot something. But then I couldn't figure out how to tell if @login_required had been applied to a view...

那么,正确的方法是什么?感谢您的帮助!

So, what's the right way to do this? Thanks for the help!

推荐答案

中间件可能是您最好的选择。我以前使用过这段代码,从其他地方的代码段修改:

Middleware may be your best bet. I've used this piece of code in the past, modified from a snippet found elsewhere:

import re

from django.conf import settings
from django.contrib.auth.decorators import login_required


class RequireLoginMiddleware(object):
    """
    Middleware component that wraps the login_required decorator around
    matching URL patterns. To use, add the class to MIDDLEWARE_CLASSES and
    define LOGIN_REQUIRED_URLS and LOGIN_REQUIRED_URLS_EXCEPTIONS in your
    settings.py. For example:
    ------
    LOGIN_REQUIRED_URLS = (
        r'/topsecret/(.*)$',
    )
    LOGIN_REQUIRED_URLS_EXCEPTIONS = (
        r'/topsecret/login(.*)$',
        r'/topsecret/logout(.*)$',
    )
    ------
    LOGIN_REQUIRED_URLS is where you define URL patterns; each pattern must
    be a valid regex.

    LOGIN_REQUIRED_URLS_EXCEPTIONS is, conversely, where you explicitly
    define any exceptions (like login and logout URLs).
    """
    def __init__(self):
        self.required = tuple(re.compile(url) for url in settings.LOGIN_REQUIRED_URLS)
        self.exceptions = tuple(re.compile(url) for url in settings.LOGIN_REQUIRED_URLS_EXCEPTIONS)

    def process_view(self, request, view_func, view_args, view_kwargs):
        # No need to process URLs if user already logged in
        if request.user.is_authenticated():
            return None

        # An exception match should immediately return None
        for url in self.exceptions:
            if url.match(request.path):
                return None

        # Requests matching a restricted URL pattern are returned
        # wrapped with the login_required decorator
        for url in self.required:
            if url.match(request.path):
                return login_required(view_func)(request, *view_args, **view_kwargs)

        # Explicitly return None for all non-matching requests
        return None

然后在settings.py列表中您要保护的基本URL:

Then in settings.py, list the base URLs you want to protect:

LOGIN_REQUIRED_URLS = (
    r'/private_stuff/(.*)$',
    r'/login_required/(.*)$',
)

只要您的站点遵循需要验证的页面的URL约定,该模型就可以正常工作。如果这不是一对一的,那么您可以选择修改中间件以适应您的情况。

As long as your site follows URL conventions for the pages requiring authentication, this model will work. If this isn't a one-to-one fit, you may choose to modify the middleware to suit your circumstances more closely.

我喜欢这种方法 - 除了删除使用 @login_required 装饰器乱码的必要性 - 就是如果验证方案发生变化,你可以有一个地方进行全局更改。

What I like about this approach - besides removing the necessity of littering the codebase with @login_required decorators - is that if the authentication scheme changes, you have one place to go to make global changes.

这篇关于使Django的login_required成为默认的最佳方式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆