2

ログイン試行の失敗時に、ユーザーが非アクティブだったか、パスワードが間違っていたか、またはユーザーが見つからなかったかを示すエラー メッセージを表示する必要があります。API に対して認証を行っているため、カスタム認証バックエンドを作成しました。現時点では、クライアントのログインが機能していることを証明するために、UserNotFoundError、InactiveUserError、および InvalidPasswordError という例外を発生させています。

それは正しい方法ではないと確信しています.Djangoの認証ビューを使用したい場合、とにかくそれらの例外をキャッチする方法がありません.

独自の認証ビューを作成する必要があると思います。しかし、もっと良い方法はありますか?

(ログインに失敗した理由を示すのは安全ではないことはわかっていますが、そうしなければなりません。)

4

2 に答える 2

3

これは完全にテストされておらず、動作することが保証されていませんが、これらの線に沿って何かを試すことができます。このソリューションの唯一の注意点は、バックエンドが最後に使用された認証バックエンド(または使用された唯一の認証バックエンド)でなければならないことです。

contrib.auth.views.authenticateメソッドは、authentication_formの引数を取ります。つまり、contrib.auth.forms.AuthenticationFormを拡張する独自のフォームでオーバーライドできるはずです。その形式は、バックエンドのauthenticate()メソッドを呼び出すものです。したがって、バックエンドでは、ユーザーインスタンスと、認証が失敗した理由の「失敗」ステータスと「失敗理由」の両方を含むカスタムオブジェクトを返すことができます。

カスタムオブジェクトのステータスが失敗の場合、例外を除いてValidationErrorをスローできます。その時点で、ログインビューはユーザーのそれ以上の処理を行いません。

また、form.get_user()をオーバーライドして、カスタムオブジェクトではなく、実際のUserインスタンスを返すようにしてください。

于 2012-07-14T02:02:51.727 に答える
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)

ノート:

  • この例ではdjango-axesを使用しています
  • 明らかなセキュリティ上の理由から、不正なクレデンシャルについてユーザー固有のエラーを表示することはお勧めできません。
于 2012-07-14T14:15:10.023 に答える