
本教程详细指导如何在django rest framework中使用自定义用户模型实现基于邮箱和密码的登录认证。文章涵盖自定义用户模型、自定义认证后端、登录序列化器和api视图的配置,并重点解析了认证后端中常见的`usermodel`引用错误及`authenticate`方法的正确返回逻辑,确保系统能够准确验证用户身份。
在Django项目中,尤其是在构建RESTful API时,经常需要使用自定义用户模型来满足特定的业务需求,例如使用邮箱而非默认的用户名进行登录。本教程将详细介绍如何配置一个基于邮箱和密码的登录系统,并解决在自定义认证后端中可能遇到的常见问题。
首先,我们需要一个自定义用户模型,它继承自AbstractBaseUser和PermissionsMixin,并将email字段设为唯一的用户名。
# your_app_name/models.py
from django.db import models
from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin
from django.utils.translation import gettext_lazy as _
from .managers import CustomUserManager # 假设你有一个自定义的用户管理器
class CustomUser(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(_("email address"), unique=True)
is_staff = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
date_joined = models.DateTimeField(auto_now_add=True)
is_company = models.BooleanField(blank=True, null=True)
USERNAME_FIELD = "email" # 指定使用email作为登录用户名
REQUIRED_FIELDS = [] # 对于AbstractBaseUser,email是USERNAME_FIELD,不需要在这里重复
objects = CustomUserManager() # 使用自定义的用户管理器
def __str__(self):
return self.email注意事项:
在项目的settings.py文件中,你需要指定Django使用你的自定义用户模型。
# your_project_name/settings.py AUTH_USER_MODEL = 'your_app_name.CustomUser'
Django的authenticate函数依赖于AUTHENTICATION_BACKENDS设置中列出的认证后端。为了实现通过邮箱登录,我们需要创建一个自定义的认证后端。
# your_app_name/backends.py
from django.contrib.auth.backends import ModelBackend
from django.contrib.auth import get_user_model
from django.db.models import Q, MultipleObjectsReturned
# 动态获取当前项目配置的用户模型,这是最佳实践
User = get_user_model()
class EmailBackend(ModelBackend):
def authenticate(self, request, username=None, password=None, **kwargs):
try:
# 使用 Q 对象进行不区分大小写的邮箱匹配
user = User.objects.get(Q(email__iexact=username))
except User.DoesNotExist:
# 如果用户不存在,应返回 None,而不是尝试设置密码
return None
except MultipleObjectsReturned:
# 如果存在多个匹配的用户,通常返回第一个
return User.objects.filter(email=username).order_by('id').first()
else:
# 验证密码并检查用户是否可认证
if user.check_password(password) and self.user_can_authenticate(user):
return user
# 认证失败(如密码不匹配)时,也应返回 None
return None
def get_user(self, user_id):
try:
user = User.objects.get(pk=user_id)
except User.DoesNotExist:
return None
return user if self.user_can_authenticate(user) else None关键修正和解释:
在settings.py中,将你的自定义认证后端添加到AUTHENTICATION_BACKENDS列表中。通常,自定义后端应放在默认后端之前,以便优先处理。
# your_project_name/settings.py
AUTHENTICATION_BACKENDS = [
'your_app_name.backends.EmailBackend', # 你的自定义后端
'django.contrib.auth.backends.ModelBackend', # Django默认的ModelBackend
]登录序列化器用于验证请求中的邮箱和密码数据。
# your_app_name/serializers.py
from rest_framework import serializers
from .models import CustomUser
class LoginSerializer(serializers.Serializer): # 继承 serializers.Serializer 即可
email = serializers.EmailField()
password = serializers.CharField(write_only=True) # 密码不应被序列化输出
# 如果需要,可以添加一个 validate 方法来验证邮箱是否存在,但 authenticate 方法会处理
# def validate(self, data):
# email = data.get('email')
# password = data.get('password')
# if not email or not password:
# raise serializers.ValidationError("Email and password are required.")
# return data
注意事项:
登录API视图将接收客户端发送的邮箱和密码,调用authenticate函数进行认证,并在成功后返回认证令牌。
# your_app_name/views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from rest_framework.authtoken.models import Token
from django.contrib.auth import authenticate # 导入Django的authenticate函数
from .serializers import LoginSerializer
from .models import CustomUser # 导入CustomUser模型
class LoginAPIView(APIView):
def post(self, request):
serializer = LoginSerializer(data=request.data)
if serializer.is_valid():
email = serializer.validated_data["email"]
password = serializer.validated_data["password"]
# 调用Django的authenticate函数,它会遍历所有注册的认证后端
user = authenticate(request, username=email, password=password)
if user is not None:
# 认证成功,获取或创建Token
token, created = Token.objects.get_or_create(user=user)
response_data = {
"status": status.HTTP_200_OK,
"message": "success",
"data": {
"Token": token.key
}
}
return Response(response_data, status=status.HTTP_200_OK)
else:
# 认证失败
response_data = {
"status": status.HTTP_401_UNAUTHORIZED,
"message": "Invalid Email or Password",
}
return Response(response_data, status=status.HTTP_401_UNAUTHORIZED)
else:
# 序列化器验证失败
response_data = {
"status": status.HTTP_400_BAD_REQUEST,
"message": "Bad Request",
"data": serializer.errors
}
return Response(response_data, status=status.HTTP_400_BAD_REQUEST)重要改进:
最后,将登录视图添加到你的urls.py中。
# your_app_name/urls.py
from django.urls import path
from .views import LoginAPIView
urlpatterns = [
path('login/', LoginAPIView.as_view(), name='login'),
]
# your_project_name/urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('api/', include('your_app_name.urls')),
]通过以上步骤,你已经成功地在Django REST Framework中设置了一个使用自定义用户模型和邮箱/密码进行认证的登录系统。核心在于正确配置AUTH_USER_MODEL,并实现一个健壮的自定义认证后端,该后端能够通过get_user_model()获取用户模型,并在认证失败时返回None。同时,登录API视图应使用authenticate函数,并妥善处理认证成功和失败的情况,包括令牌的获取或创建。遵循这些最佳实践将确保你的认证系统安全、可靠且易于维护。
以上就是Django REST Framework自定义用户模型实现邮箱登录认证教程的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号