Python Django中间件,具有登录名和密码,可隐藏所有网站页面

Python Django中间件,具有登录名和密码,可隐藏所有网站页面,python,django,middleware,Python,Django,Middleware,我编写了以下中间件,它呈现表单并要求用户登录和密码。中间件应应用于整个网站: class InviteLoginForWebsiteMiddleware(object): def process_request(self, request): if request.session.get('has_invite') == True: return None form = WebsiteLoginForm() ex

我编写了以下中间件,它呈现表单并要求用户登录和密码。中间件应应用于整个网站:

class InviteLoginForWebsiteMiddleware(object):

    def process_request(self, request):
        if request.session.get('has_invite') == True:
            return None

        form = WebsiteLoginForm()
        extra_context = dict()
        extra_context['form'] = form
        template_name = 'websiteLogin.html'

        if request.method == "POST":
            form = WebsiteLoginForm(request.POST)
            if form.is_valid():
                login = form.cleaned_data['login']
                password = form.cleaned_data['password']

                if login == "mylogin" and password == "mypassword":
                    request.session['has_inv'] = True
                    return None

        return ExtraContextTemplateView.as_view(template_name=template_name, extra_context=extra_context)(request)
此解决方案的问题是,当我在进程内创建表单时,呈现页面上缺少请求csrf令牌。我一直在寻找答案,发现开发人员建议生成表单并在process_视图中处理它

将所有代码移动到process_视图后,如:

代码开始工作,生成了csrf令牌,我可以提交带有登录名和密码的表单

当用户进入无效页面(如www.mysite.com/notworkingurl/)时,就会出现问题。在这种情况下,process_视图不工作,出现404错误,用户被重定向到部分显示web应用程序界面的页面。当然,我希望中间件应该隐藏应用程序的所有页面

再一次:

  • 当我将代码放在process_请求中时,我可以捕获任何调用 到网站上的任何页面,但不呈现csrf。因此,当用户提交表单时引发csrf错误
  • 当我 process_view中的代码所有内容都适用于中的页面 如果它存在的话。如果它不存在,用户将根据 404和其他异常URL。我不希望这种重定向发生
  • 有人能提出解决这个问题的好办法吗

    解决方案:

    感谢@knbk的建议,一个可能的解决方案是使用csrf_保护装饰器。为了实现这一想法,我对视图类进行了如下修改:

    class ExtraContextTemplateViewCsrfProtect(TemplateView):
      extra_context = None
    
      @method_decorator(csrf_protect)
      def dispatch(self, request, *args, **kwargs):
        return super(ExtraContextTemplateViewCsrfProtect, self).dispatch(request, *args, **kwargs)
    
      def get_context_data(self, *args, **kwargs):
        context = super(ExtraContextTemplateViewCsrfProtect, self).get_context_data(*args, **kwargs)
        if self.extra_context:
          context.update(self.extra_context)
        return context
    
      post = TemplateView.get
    

    也许您可以尝试使用登录所需的中间件:

    from django.http import HttpResponseRedirect
    from django.conf import settings
    from re import compile
    
    EXEMPT_URLS = [compile(settings.LOGIN_URL.lstrip('/'))]
    if hasattr(settings, 'LOGIN_EXEMPT_URLS'):
        EXEMPT_URLS += [compile(expr) for expr in settings.LOGIN_EXEMPT_URLS]
    
    class LoginRequiredMiddleware:
        """
        Middleware that requires a user to be authenticated to view any page other
        than LOGIN_URL. Exemptions to this requirement can optionally be specified
        in settings via a list of regular expressions in LOGIN_EXEMPT_URLS (which
        you can copy from your urls.py).
    
        Requires authentication middleware and template context processors to be
        loaded. You'll get an error if they aren't.
        """
        def process_request(self, request):
            assert hasattr(request, 'user'), "The Login Required middleware\
     requires authentication middleware to be installed. Edit your\
     MIDDLEWARE_CLASSES setting to insert\
     'django.contrib.auth.middlware.AuthenticationMiddleware'. If that doesn't\
     work, ensure your TEMPLATE_CONTEXT_PROCESSORS setting includes\
     'django.core.context_processors.auth'."
            if not request.user.is_authenticated():
                path = request.path_info.lstrip('/')
                if not any(m.match(path) for m in EXEMPT_URLS):
                    return HttpResponseRedirect(settings.LOGIN_URL)
    

    settings.py:

    LOGIN_URL = '/login/'
    
    LOGIN_EXEMPT_URLS = (
     r'^about\.html$',
     r'^legal/', # allow any URL under /legal/*
    ) 
    
    MIDDLEWARE_CLASSES = (
        # ...
        'python.path.to.LoginRequiredMiddleware',
    )                    
    
    登录所需的中间件:

    from django.http import HttpResponseRedirect
    from django.conf import settings
    from re import compile
    
    EXEMPT_URLS = [compile(settings.LOGIN_URL.lstrip('/'))]
    if hasattr(settings, 'LOGIN_EXEMPT_URLS'):
        EXEMPT_URLS += [compile(expr) for expr in settings.LOGIN_EXEMPT_URLS]
    
    class LoginRequiredMiddleware:
        """
        Middleware that requires a user to be authenticated to view any page other
        than LOGIN_URL. Exemptions to this requirement can optionally be specified
        in settings via a list of regular expressions in LOGIN_EXEMPT_URLS (which
        you can copy from your urls.py).
    
        Requires authentication middleware and template context processors to be
        loaded. You'll get an error if they aren't.
        """
        def process_request(self, request):
            assert hasattr(request, 'user'), "The Login Required middleware\
     requires authentication middleware to be installed. Edit your\
     MIDDLEWARE_CLASSES setting to insert\
     'django.contrib.auth.middlware.AuthenticationMiddleware'. If that doesn't\
     work, ensure your TEMPLATE_CONTEXT_PROCESSORS setting includes\
     'django.core.context_processors.auth'."
            if not request.user.is_authenticated():
                path = request.path_info.lstrip('/')
                if not any(m.match(path) for m in EXEMPT_URLS):
                    return HttpResponseRedirect(settings.LOGIN_URL)
    

    您的中间件不仅缺少csrf令牌,而且容易受到csrf攻击

    如果要使用此模式,而不是重定向到单个登录视图,则应将所有表单逻辑移到实际视图中。然后,您可以使用
    csrf\u protect
    保护视图免受csrf攻击,这也使您能够使用模板中的令牌:

    class InviteLoginForWebsiteMiddleware(object):
    
        def process_request(self, request):
            if request.session.get('has_invite') == True:
                return None
    
            return csrf_protect(CustomLoginView.as_view())(request)
    

    但是,我建议采用matox建议的方法

    您是否将404请求重定向到
    进程视图
    ?否,我有自定义URL,在引发404异常时重定向到404视图。当我的中间件代码在“process\u view”中工作时,用户输入的url不正确,终端视图不存在,并且引发404。这很奇怪。流程视图的哪一行引发了404异常?我编辑了我之前的答案。请看一看!显示的进程视图不会引发任何异常,但当用户输入不正确的url时,会再次发生异常。谢谢!我也在我的应用程序中使用它。但如果我要玩它,那么我必须打开至少一个在我的应用程序中创建帐户的可能性。这不是我想要的。我正在寻找一种可以在需要时轻松打开或关闭的add-hoc解决方案。您可以通过注释
    中间件类
    中的中间件来轻松关闭它。是的,这也是正确的,就像任何其他中间件一样。您可以根据自己的情况替换
    请求.用户
    。这个函数只是将任何未经授权的请求重定向到您的登录页面。我相信这就是你本质上需要的。这里的问题是,我必须提供访问帐户的功能,所以基本上,用户应该能够创建配置文件,修改它们等等。这个功能已经在网站上展示了,但我不想重构代码。在这种情况下,整个应用程序的简单包装将更适合。同时,你的解决方案更专业、更稳健。是的,你是对的。它将非常容易受到攻击,但在我的情况下,这将是好的,因为,正如我写给matox的,这将是唯一的添加临时解决方案,以隐藏网站的第一次与能力,打开或关闭它的时间。如果直接使用您的代码,那么它不起作用,但是如果修改它并将csrf_protect移动到我的TemplateView中,那么问题就解决了。