Django集成django-axes遇AxesBackend请求参数错误求助
Django使用django-axes登录报错AxesBackend requires a request as an argument to authenticate
问题背景
为Django站点配置django-axes实现登录次数限制后,登录时无论密码正确与否均触发错误:AxesBackend requires a request as an argument to authenticate,尽管在auth.authenticate中已传递request参数。
相关代码
settings.py
INSTALLED_APPS = [ ... 'axes', ] MIDDLEWARE = [ ... 'axes.middleware.AxesMiddleware', ] AXES_FAILURE_LIMIT = 4 AXES_RESET_ON_SUCCESS = True AXES_COOLOFF_TIME = 1 AUTHENTICATION_BACKENDS = [ 'axes.backends.AxesBackend', # Axes must be first 'django.contrib.auth.backends.ModelBackend', ] AUTH_USER_MODEL = "users.User" LOGIN_URL = "/user/login/"
views.py
from django.contrib import auth, messages def login(request): if request.method == "POST": form = UserLoginForm(data=request.POST) if form.is_valid(): username = request.POST["username"] password = request.POST["password"] user = auth.authenticate(request=request, username=username, password=password) if user: auth.login(request, user) redirect_page = request.POST.get("next", None) if redirect_page and redirect_page != reverse("user:logout"): return HttpResponseRedirect(request.POST.get("next")) return HttpResponseRedirect(reverse("main:main_page")) else: form = UserLoginForm() context = {"title": "Вход", "form": form} return render(request, "users/login.html", context)
forms.py
from django import forms from django.contrib.auth.forms import ( AuthenticationForm, UserCreationForm, UserChangeForm, ) from users.models import User class UserLoginForm(AuthenticationForm): username = forms.CharField() password = forms.CharField() class Meta: model = User fields = ["username", "password"]
依赖版本
Django==5.0.4 django-axes==6.5.2
完整报错栈
Traceback (most recent call last): File "c:\Users\danii\OneDrive\Рабочий стол\coins\Project Bismuth\venv\Lib\site-packages\django\core\handlers\exception.py", line 55, in inner response = get_response(request) ^^^^^^^^^^^^^^^^^^^^^ File "c:\Users\danii\OneDrive\Рабочий стол\coins\Project Bismuth\venv\Lib\site-packages\django\core\handlers\base.py", line 197, in _get_response response = wrapped_callback(request, *callback_args, **callback_kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\danii\OneDrive\Рабочий стол\coins\Project Bismuth\bismuth\users\views.py", line 17, in login if form.is_valid(): ^^^^^^^^^^^^^^^ File "c:\Users\danii\OneDrive\Рабочий стол\coins\Project Bismuth\venv\Lib\site-packages\django\forms\forms.py", line 197, in is_valid return self.is_bound and not self.errors ^^^^^^^^^^^ File "c:\Users\danii\OneDrive\Рабочий стол\coins\Project Bismuth\venv\Lib\site-packages\django\forms\forms.py", line 192, in errors self.full_clean() File "c:\Users\danii\OneDrive\Рабочий стол\coins\Project Bismuth\venv\Lib\site-packages\django\forms\forms.py", line 328, in full_clean self._clean_form() File "c:\Users\danii\OneDrive\Рабочий стол\coins\Project Bismuth\venv\Lib\site-packages\django\forms\forms.py", line 349, in _clean_form cleaned_data = self.clean() ^^^^^^^^^^^^ File "c:\Users\danii\OneDrive\Рабочий стол\coins\Project Bismuth\venv\Lib\site-packages\django\contrib\auth\forms.py", line 250, in clean self.user_cache = authenticate( ^^^^^^^^^^^^^ File "c:\Users\danii\OneDrive\Рабочий стол\coins\Project Bismuth\venv\Lib\site-packages\django\views\decorators\debug.py", line 75, in sensitive_variables_wrapper return func(*func_args, **func_kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "c:\Users\danii\OneDrive\Рабочий стол\coins\Project Bismuth\venv\Lib\site-packages\django\contrib\auth\__init__.py", line 79, in authenticate user = backend.authenticate(request, **credentials) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "c:\Users\danii\OneDrive\Рабочий стол\coins\Project Bismuth\venv\Lib\site-packages\axes\helpers.py", line 615, in inner return func(*func_args, **func_kwargs) ^^^^^^^^^^^^^^^^^^^^^ File "c:\Users\danii\OneDrive\Рабочий стол\coins\Project Bismuth\venv\Lib\site-packages\axes\backends.py", line 46, in authenticate raise AxesBackendRequestParameterRequired( axes.exceptions.AxesBackendRequestParameterRequired: AxesBackend requires a request as an argument to authenticate [07/Oct/2024 10:27:42] "POST /user/login/ HTTP/1.1" 500 125895
解决方案
从报错栈可以看出,错误触发在form.is_valid()执行阶段——即AuthenticationForm的默认clean方法中调用authenticate时,没有传递request参数,而非你自己写的auth.authenticate代码。
1. 重写表单的clean方法并传入request
修改forms.py,重写__init__方法接收request,并重写clean方法在调用authenticate时传入request:
from django import forms from django.contrib.auth.forms import AuthenticationForm from django.contrib.auth import authenticate from users.models import User class UserLoginForm(AuthenticationForm): username = forms.CharField() password = forms.CharField() class Meta: model = User fields = ["username", "password"] def __init__(self, request=None, *args, **kwargs): super().__init__(request=request, *args, **kwargs) self.request = request def clean(self): username = self.cleaned_data.get('username') password = self.cleaned_data.get('password') if username and password: # 关键:调用authenticate时传入request参数 self.user_cache = authenticate(request=self.request, username=username, password=password) if self.user_cache is None: raise self.get_invalid_login_error() else: self.confirm_login_allowed(self.user_cache) return self.cleaned_data
2. 修改视图中表单的初始化代码
在views.py中,初始化表单时传入request参数:
def login(request): if request.method == "POST": # 修改表单初始化,传入request form = UserLoginForm(request=request, data=request.POST) if form.is_valid(): # 后续代码不变 username = request.POST["username"] password = request.POST["password"] user = auth.authenticate(request=request, username=username, password=password) # ... 其余代码保持原样 else: # GET请求时也传入request form = UserLoginForm(request=request) context = {"title": "Вход", "form": form} return render(request, "users/login.html", context)
3. 额外检查项
- 确保
AxesMiddleware在MIDDLEWARE中的位置正确,建议放在django.contrib.sessions.middleware.SessionMiddleware之后,django.middleware.common.CommonMiddleware之前 - 执行
python manage.py migrate命令,确保django-axes的数据库表已创建 - 确认
AUTHENTICATION_BACKENDS中axes.backends.AxesBackend排在第一位
内容的提问来源于stack exchange,提问作者DANIRU
相关产品推荐
相关产品推荐

