如果用户在 Django 中有 3 次或更少的失败登录尝试,则隐藏 reCatpcha 错误消息

Hide reCatpcha error message if user has 3 or less failed login attempts in Django

我是 Django 的初学者,有一个登录页面,当用户登录失败次数超过 3 次时,登录页面将显示 reCaptcha,效果很好。

但是,无论是否成功登录,我的登录页面仍然在每次登录尝试时显示无效验证码的错误消息(此错误消息来自 recaptcha 装饰器 - 'Invalid reCAPTCHA. Please try again.',尽管让我按我的方式登录已经编码)- 我想从我的登录页面隐藏这个特定的错误消息,除非用户有超过 3 次失败的登录尝试以及我如何在页面上显示实际的验证码。

我正在使用 django axes 检查失败的登录尝试,并禁用了不需要的用户锁定。

非常感谢对此的任何帮助。

网址

from django.urls import path, include

from django.contrib.auth import views as auth_views

from . import views
from .views import RequestPasswordResetEmail, CompletePasswordReset
#from .forms import EmailValidationOnForgotPassword

urlpatterns = [
    path('login/', views.loginpage, name="login"),
    path('logout/', views.logoutuser, name="logout"),
]

重新验证 decorator.py

from functools import wraps

from django.conf import settings
from django.contrib import messages

import requests

def check_recaptcha(view_func):
    @wraps(view_func)
    def _wrapped_view(request, *args, **kwargs):
        request.recaptcha_is_valid = None
        if request.method == 'POST':
            recaptcha_response = request.POST.get('g-recaptcha-response')
            data = {
                'secret': settings.RECAPTCHA_PRIVATE_KEY,
                'response': recaptcha_response
            }
            r = requests.post('https://www.google.com/recaptcha/api/siteverify', data=data)
            result = r.json()
            if result['success']:
                request.recaptcha_is_valid = True
            else:
                request.recaptcha_is_valid = False
                messages.error(request, 'Invalid reCAPTCHA. Please try again.')
        return view_func(request, *args, **kwargs)
    return _wrapped_view

查看

from django.conf import settings
from .decorators import check_recaptcha
from django.shortcuts import render, redirect
from django.contrib import messages, auth
from django.contrib.auth import authenticate, login, logout
from django.views import View
from .decorators import check_recaptcha
from axes.decorators import axes_dispatch
from axes.attempts import (
    clean_expired_user_attempts,
    get_user_attempts,
    reset_user_attempts,
)


@axes_dispatch
@check_recaptcha
def loginpage(request, credentials: dict = None):

    attempts_list = get_user_attempts(request, credentials)

    attempt_count = max(
        (
                attempts.aggregate(Sum("failures_since_start"))[
                    "failures_since_start__sum"
                ]
                or 0
        )
        for attempts in attempts_list
    )
    print(attempt_count)

    attempt_count = attempt_count +1

    context = {'attempt_count': attempt_count}

    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')

        user = authenticate(request, username=username, password=password)

        if user is not None:

            if user.is_active and attempt_count <= 3:
                request.recaptcha_is_valid = True
                login(request, user)
                return redirect('home')

            if user.is_active and attempt_count > 3 and request.recaptcha_is_valid:
                login(request, user)
                return redirect('home')

            if not user.is_active:
                messages.error(request, 'Account for this User has not been Activated.')
        else:
            messages.error(request, 'Username or Password is Incorrect.')

    print(context)
    return render(request, 'login.html', context)

模板登录

{% extends 'base.html' %}

{% block title %}User Login{% endblock %}

{% block content %}
    <div class="d-flex justify-content-center">
        <h3 id="form-title">Login</h3>
    </div>
    <div class="d-flex justify-content-center form_container">
        <form method="POST" action="">
            {% csrf_token %}

<div align="center">
            <div class="input-group mb-2">
                <div class="input-group-append">
                    <span class="input-group-text"><i class="fas fa-user"></i></span>
                </div>
                <input type="text" name="username" placeholder="Email" class="form-control">
            </div>



            <div class="input-group mb-3">
                <div class="input-group-append">
                    <span class="input-group-text"><i class="fas fa-key"></i></span>
                </div>
                <input type="password" name="password" placeholder="Password" class="form-control">
            </div>
</div>


 {% include 'recaptcha.html' %}


            <div class="d-flex justify-content-center mt-3 login_container">
                <input class="btn login_btn" type="submit" value="Login">
            </div>



        </form>
    </div>

    {% for message in messages %}
    
    <p>{{ message }}</p> 

    {% endfor %}



    <div class="input-group mb-1">
    </div>
    <div class="mt-1">
        <div class="d-flex justify-content-center links">
            Don't have an account? <a href="{% url 'register' %}" class="ml-2">Sign Up</a>
        </div>
        <div class="d-flex justify-content-center links">
            Forgot Password? <a href="{% url 'request-password' %}" class="ml-2">Reset Password</a>
        </div>
    </div>

{% endblock content %}

我设法通过将装饰器更新为仅在 4 次登录尝试失败后显示错误消息来解决此问题,如下所示:

重新验证 decorator.py

from django.conf import settings
from django.contrib import messages
from django.db.models import Sum
from functools import wraps


from axes.attempts import (
    get_user_attempts,
)

import requests


def check_recaptcha(view_func, credentials: dict = None):
    @wraps(view_func)
    def _wrapped_view(request, *args, **kwargs):

        attempts_list = get_user_attempts(request, credentials)

        attempt_count = max(
            (
                    attempts.aggregate(Sum("failures_since_start"))[
                        "failures_since_start__sum"
                    ]
                    or 0
            )
            for attempts in attempts_list
        )
        print(attempt_count)

        attempt_count = attempt_count + 1



        request.recaptcha_is_valid = None
        if request.method == 'POST':
            recaptcha_response = request.POST.get('g-recaptcha-response')
            data = {
                'secret': settings.RECAPTCHA_PRIVATE_KEY,
                'response': recaptcha_response
            }
            r = requests.post('https://www.google.com/recaptcha/api/siteverify', data=data)
            result = r.json()
            if result['success']:
                request.recaptcha_is_valid = True
            else:
                request.recaptcha_is_valid = False

                if attempt_count > 3+1:
                    messages.error(request, 'Invalid reCAPTCHA. Please try again.')


        return view_func(request, *args, **kwargs)
    return _wrapped_view

一切如我所愿!