Django自定义认证后端登录报错:缺少request参数求助
自定义认证后端登录报错:TypeError: authenticate()缺少request参数
登录时触发如下异常:
Internal Server Error: /login/ Traceback (most recent call last): File "C:\Users\G-FIVE\Desktop\Projects\revenue\venv\Lib\site-packages\django\core\handlers\exception.py", line 55, in inner response = get_response(request) ^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\G-FIVE\Desktop\Projects\revenue\venv\Lib\site-packages\django\core\handlers\base.py", line 197, in _get_response response = wrapped_callback(request, *callback_args, **callback_kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "D:\Projects\revenue\authentication\views.py", line 12, in login usuario = UsuarioAuthBackend.authenticate(request, email=email, password=password) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ TypeError: UsuarioAuthBackend.authenticate() missing 1 required positional argument: 'request' [09/Jun/2023 10:47:15] "POST /login/ HTTP/1.1" 500 66119
自定义用户模型、认证后端、登录视图及配置均已设置,但系统提示缺少request参数,相关代码如下:
自定义用户模型
from django.db import models from django.contrib.auth.models import AbstractBaseUser, BaseUserManager # choices CALIFICACION_USUARIO_CHOICES = [ (0,0), (1,1), (2,2), (3,3), (4,4) ] # Create your models here. class UsuarioManager(BaseUserManager): use_in_migrations = True def _create_user(self, email, password, **extra_fields): if not email: raise ValueError('El usuario debe tener un correo electrónico') email = self.normalize_email(email) usuario = self.model(email=email, **extra_fields) usuario.set_password(password) usuario.save(using=self._db) return usuario def create_user(self, email=None, password=None, **extra_fields): extra_fields.setdefault('is_staff', True) extra_fields.setdefault('is_superuser', False) return self._create_user(email, password, **extra_fields) def create_superuser(self, email, password, **extra_fields): extra_fields.setdefault('is_staff', True) extra_fields.setdefault('is_superuser', True) if extra_fields.get('is_staff') is not True: raise ValueError('Superusuario debe tener la propiedad "is_staff=True"') if extra_fields.get('is_superuser') is not True: raise ValueError('Superusuario debe tener la propiedad "is_superuser=True"') return self._create_user(email, password, **extra_fields) class Usuario(AbstractBaseUser): first_name = models.CharField(verbose_name='Nombre', max_length=255) last_name = models.CharField(verbose_name='Apellidos', max_length=255, blank=True, null=True) email = models.EmailField(verbose_name='Correo', unique=True, max_length=255) cedula = models.CharField(verbose_name='Cédula de Identidad', null=False, blank=False, max_length=255) telefono = models.CharField(verbose_name='Teléfono', max_length=255, null=False, blank=False) calificacion = models.SmallIntegerField(verbose_name='Calificación', null=False, blank=False, choices=CALIFICACION_USUARIO_CHOICES, default=0) direccion = models.TextField(verbose_name='Dirección', null=True, blank=True) foto_perfil = models.ImageField(verbose_name='Foto de perfil', max_length=255, null=True, blank=True, upload_to='perfil/') terminos_y_condiciones = models.BooleanField(verbose_name='Términos y condiciones', default=False) is_active = models.BooleanField(verbose_name='active',default=True) is_staff = models.BooleanField(verbose_name='staff status', default=False) is_superuser = models.BooleanField(verbose_name='superuser status', default=False) objects = UsuarioManager() USERNAME_FIELD = 'email' def __str__(self): return f'{self.first_name} {self.last_name}' def has_perm(self,perm,obj=None): return True def has_module_perms(self,app_label): return True def get_email_user(self): return self.email.lower() def save(self, *args, **kwargs): self.email = self.email.lower() return super(Usuario, self).save(*args, **kwargs) class Meta: verbose_name = 'Usuario' verbose_name_plural = 'Usuarios' ordering = ['-id']
自定义认证后端
from django.contrib.auth.backends import ModelBackend from authentication.models import Usuario class UsuarioAuthBackend(ModelBackend): def authenticate(self, request, **kwargs): email = kwargs['email'] password = kwargs['password'] try: usuario = Usuario.objects.get(email=email) if usuario.check_password(password) is True: return usuario except Usuario.DoesNotExist: return None
登录视图
from django.shortcuts import render, redirect from django.contrib.auth import login, logout from authentication.authentication import UsuarioAuthBackend from authentication.forms import FormUsuario # Create your views here. def login(request): if request.method == 'POST': email = request.POST['email'] password = request.POST['password'] usuario = UsuarioAuthBackend.authenticate(request, email=email, password=password) if usuario is not None: login(request, usuario) return redirect('home') return render(request, 'login.html')
settings.py配置
AUTHENTICATION_BACKENDS = [ 'django.contrib.auth.backends.ModelBackend', 'authentication.authentication.UsuarioAuthBackend' ]
解决方案
问题出在登录视图中直接调用了UsuarioAuthBackend.authenticate类方法,而authenticate是实例方法,需要先实例化类再调用,或者更规范的是使用Django内置的django.contrib.auth.authenticate函数,它会自动遍历你配置的认证后端进行验证。
方案一(推荐):使用Django内置authenticate函数
修改登录视图代码:
from django.shortcuts import render, redirect from django.contrib.auth import login, logout, authenticate # 导入authenticate from authentication.forms import FormUsuario def login(request): if request.method == 'POST': email = request.POST['email'] password = request.POST['password'] # 使用Django内置的authenticate函数,自动使用配置的后端验证 usuario = authenticate(request, email=email, password=password) if usuario is not None: login(request, usuario) return redirect('home') return render(request, 'login.html')
方案二:手动实例化后端类
如果一定要手动调用自定义后端的方法,需要先实例化:
# 在视图中替换原来的调用代码 backend = UsuarioAuthBackend() usuario = backend.authenticate(request, email=email, password=password)
推荐使用第一种方案,符合Django标准认证流程,能自动处理多后端验证逻辑。
内容的提问来源于stack exchange,提问作者Angel Daniel Ascanio Salazar
相关产品推荐
相关产品推荐

