带登录名和密码的Django中间件,隐藏了所有网站页面

时间:2016-11-23 13:15:19

标签: python django middleware

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

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)

此解决方案的问题在于,当我在 process_request 中创建表单时,在呈现的页面上缺少csrf标记。我找到了答案,发现开发人员建议生成表单并在 process_view

中处理它

将所有代码移入 process_view 之后:

def process_view(self, request, view_func, view_args, view_kwargs):
    if request.session.get('has_inv') == 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令牌,我可以使用登录名和密码提交表单。

当用户输入 www.mysite.com/notworkingurl / 等无效页面时,会出现问题。在这种情况下, process_view 不起作用,引发404错误,用户被重定向到页面,该页面部分显示了Web应用程序的界面。当然,我希望中间件应该隐藏应用程序的所有页面。

再次:

  1. 当我将代码放在 process_request 中时,我可以接听任何电话 到网站上的任何页面,但不呈现csrf。因此,当用户提交表单时会引发csrf错误。
  2. 我放的时候      process_view 中的代码所有内容都适用于该页面     它存在的情况。如果不存在则根据用户重定向     404和其他例外网址。我不希望这种重定向发生。
  3. 有人可以建议任何解决此问题的好方法吗?

    解决方案:

    感谢@knbk的建议,可能的解决方案之一是使用csrf_protect装饰器。为了使这个想法有效,我修改了我的视图类,如下所示:

    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
    

2 个答案:

答案 0 :(得分:0)

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

Django Login Required Middleware

settings.py:

LOGIN_URL = '/login/'

LOGIN_EXEMPT_URLS = (
 r'^about\.html$',
 r'^legal/', # allow any URL under /legal/*
) 

MIDDLEWARE_CLASSES = (
    # ...
    'python.path.to.LoginRequiredMiddleware',
)                    

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)

答案 1 :(得分:0)

您的中间件不仅缺少csrf令牌,它还容易受到CSRF攻击

如果要使用此模式,而不是重定向到单个登录视图,则应将所有表单逻辑移动到实际视图中。然后,您可以使用csrf_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建议的方法。