我编写了以下中间件,它们呈现表单并询问用户登录名和密码。中间件应该应用于整个网站:
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应用程序的界面。当然,我希望中间件应该隐藏应用程序的所有页面。
再次:
有人可以建议任何解决此问题的好方法吗?
解决方案:
感谢@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
答案 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建议的方法。