我需要在失败的登录尝试中显示一条错误消息,指出用户是否处于非活动状态,密码是否错误或未找到用户。我正在对API进行身份验证,因此我制作了自定义身份验证后端。目前,为了证明客户端登录工作正常,我提出了一些名为UserNotFoundError,InactiveUserError和InvalidPasswordError的异常。
我很确定这不是正确的方法,如果我想使用Django的auth视图,我无论如何都无法捕捉到这些异常。
我假设我需要创建自己的身份验证视图。但是,有更好的方法吗?
(我知道提供登录失败的原因并不安全,但我必须这样做。)
答案 0 :(得分:3)
这是完全未经测试的,并且无法保证可以正常工作,但您可以尝试这些方法。此解决方案唯一需要注意的是,您的后端必须是最后使用的身份验证后端(或者是唯一使用的身份验证后端)。
contrib.auth.views.authenticate方法接受authentication_form的参数,这意味着您应该能够使用扩展contrib.auth.forms.AuthenticationForm的自己的表单覆盖它。该形式调用后端的authenticate()方法。因此,在您的后端,您可以返回一些自定义对象,其中包含用户实例以及“失败”状态和“失败原因”,用于验证失败的原因。
如果您的自定义对象状态为失败,则可以抛出ValidationError,但该登录视图不会对用户进行任何进一步处理。
还要确保覆盖form.get_user(),以便它返回实际的User实例,而不是您的自定义对象。
答案 1 :(得分:0)
或者只是覆盖login(),如下:
from django.conf import settings
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.contrib.auth.views import logout
from django.http import HttpResponseRedirect
from django.template.response import TemplateResponse
from django.utils.translation import ugettext as _
from django.views.decorators.debug import sensitive_post_parameters
from django.views.decorators.cache import never_cache
from django.views.decorators.csrf import csrf_protect
# Avoid shadowing the login() and logout() views below.
from django.contrib.auth import REDIRECT_FIELD_NAME, login as auth_login
from django.contrib.auth.forms import AuthenticationForm
from django.contrib.sites.models import get_current_site
# App specific
from axes.models import AccessAttempt
@sensitive_post_parameters()
@csrf_protect
@never_cache
def login(request, template_name='registration/login.html',
redirect_field_name=REDIRECT_FIELD_NAME,
authentication_form=AuthenticationForm,
current_app=None, extra_context=None,
form_name='form'):
"""
Displays the login form and handles the login action.
"""
redirect_to = request.REQUEST.get(redirect_field_name, '')
if request.method == "POST":
form = authentication_form(data=request.POST)
if form.is_valid():
netloc = urlparse.urlparse(redirect_to)[1]
# Use default setting if redirect_to is empty
if not redirect_to:
redirect_to = settings.LOGIN_REDIRECT_URL
# Heavier security check -- don't allow redirection to a different
# host.
elif netloc and netloc != request.get_host():
redirect_to = settings.LOGIN_REDIRECT_URL
# Okay, security checks complete. Log the user in.
auth_login(request, form.get_user())
if request.session.test_cookie_worked():
request.session.delete_test_cookie()
messages.add_message(request, messages.SUCCESS, _("Welcome <strong>%s</strong>.") % [request.user.get_full_name() if request.user.get_full_name() is not u"" else request.user.username].pop())
return HttpResponseRedirect(redirect_to)
else:
if extra_context is None:
extra_context = {}
extra_context.update({'login_form_errors': True})
try:
attempt = AccessAttempt.objects.get(ip_address=request.META.get('REMOTE_ADDR', ''))
if attempt.failures_since_start < 2:
messages.add_message(request, messages.ERROR, _(u"Invalid credentials, last chance."))
if attempt.failures_since_start == 2:
messages.add_message(request, messages.ERROR, _(u"Authentication has been blocked for a 24h cooldown period."))
except AccessAttempt.DoesNotExist:
messages.add_message(request, messages.ERROR, _(u"Invalid credentials, please try again."))
else:
form = authentication_form(request)
request.session.set_test_cookie()
current_site = get_current_site(request)
context = {
form_name: form,
redirect_field_name: redirect_to,
'site': current_site,
'site_name': current_site.name,
}
if extra_context is not None:
context.update(extra_context)
return TemplateResponse(request, template_name, context,
current_app=current_app)
注释: