You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 13:37:05