Показ капчи после 5 неверных попыток входа в систему с помощью django-axes
Я начинающий Django и у меня есть страница входа и с капчей, которая работает отлично, однако я хотел бы показывать капчу в шаблоне страницы входа только после того, как пользователь ввел неправильные данные для входа после 5 попыток.
В моем шаблоне есть тег include для моей капчи, которую я предпочитаю отображать этим методом, но не уверен, что это возможно, но думал, что смогу реализовать через создание 2 отдельных представлений/шаблонов, так как мне казалось, что я смогу это сделать, но, похоже, нет.
Урлы
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('login-captcha/', views.logincaptcha, name="logincaptcha"),
path('logout/', views.logoutuser, name="logout"),
path('register/', views.registerpage, name="register"),
path('verify-email/<uidb64>/<token>', views.verify_email, name="verify_email"),
path('activate-account/<uidb64>/<token>', views.activate_account, name="activate_account"),
path('set-new-password/<uidb64>/<token>', CompletePasswordReset.as_view(), name="reset-user-password"),
path("request-reset-link/", RequestPasswordResetEmail.as_view(), name="request-password"),
]
Виды
from django.conf import settings
from .decorators import check_recaptcha
from axes.decorators import axes_dispatch
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
@axes_dispatch
def loginpage(request):
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 settings.AXES_FAILURE_LIMIT < 3:
login(request, user)
return redirect('home')
elif settings.AXES_FAILURE_LIMIT > 3:
return redirect('logincaptcha')
else:
messages.error(request, 'Account for this User has not been Activated.')
else:
messages.error(request, 'Username or Password is Incorrect.')
context = {}
return render(request, 'login.html', context)
def logincaptcha(request):
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:
login(request, user)
return redirect('home')
else:
messages.error(request, 'Account for this User has not been Activated.')
else:
messages.error(request, 'Username or Password is Incorrect.')
context = {}
return render(request, 'login_captcha.html', context)
Шаблон logincaptcha (шаблон страницы входа точно такой же, но не включает тег captcha)
{% 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>
{% include 'messages.html' %}
<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 неудачных попыток входа в систему следующим образом:
recaptcha 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
Все работает так, как мне нужно!