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

查看:42
本文介绍了使 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(...):

那很好,而且效果很好只要我们记得在任何地方添加它!可悲的是,有时我们会忘记,而失败往往并不十分明显.如果视图的唯一链接位于 @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天全站免登陆