
本教程详细指导如何在django rest framework中使用自定义用户模型实现基于邮箱和密码的登录认证。文章涵盖自定义用户模型、自定义认证后端、登录序列化器和api视图的配置,并重点解析了认证后端中常见的`usermodel`引用错误及`authenticate`方法的正确返回逻辑,确保系统能够准确验证用户身份。
在Django项目中,尤其是在构建RESTful API时,经常需要使用自定义用户模型来满足特定的业务需求,例如使用邮箱而非默认的用户名进行登录。本教程将详细介绍如何配置一个基于邮箱和密码的登录系统,并解决在自定义认证后端中可能遇到的常见问题。
1. 定义自定义用户模型
首先,我们需要一个自定义用户模型,它继承自AbstractBaseUser和PermissionsMixin,并将email字段设为唯一的用户名。
# your_app_name/models.pyfrom django.db import modelsfrom django.contrib.auth.models import AbstractBaseUser, PermissionsMixinfrom 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
注意事项:
USERNAME_FIELD = “email” 明确告诉Django使用email字段作为用户的唯一标识符进行认证。REQUIRED_FIELDS 列表为空,因为email已经是USERNAME_FIELD。你需要创建一个CustomUserManager来处理用户创建,通常它会继承BaseUserManager。
2. 配置Django使用自定义用户模型
在项目的settings.py文件中,你需要指定Django使用你的自定义用户模型。
# your_project_name/settings.pyAUTH_USER_MODEL = 'your_app_name.CustomUser'
3. 创建自定义认证后端
Django的authenticate函数依赖于AUTHENTICATION_BACKENDS设置中列出的认证后端。为了实现通过邮箱登录,我们需要创建一个自定义的认证后端。
# your_app_name/backends.pyfrom django.contrib.auth.backends import ModelBackendfrom django.contrib.auth import get_user_modelfrom 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
关键修正和解释:
User = get_user_model(): 这是最重要的一点。在自定义认证后端中,应该使用django.contrib.auth.get_user_model()来动态获取在settings.AUTH_USER_MODEL中指定的自定义用户模型。直接使用UserModel是错误的,因为UserModel不是一个预定义的全局变量。except User.DoesNotExist: return None: 当通过邮箱找不到用户时,authenticate方法应该直接返回None,表示认证失败。原始代码中尝试在except块中调用UserModel().set_password(password)是错误的,因为它会在一个不存在的用户实例上操作,并且不会正确处理认证流程。Q(email__iexact=username): 使用Q对象和iexact进行不区分大小写的邮箱匹配,提高用户体验。return None: 确保在任何认证失败的情况下(例如密码不匹配),authenticate方法都返回None。
4. 在settings.py中注册自定义认证后端
在settings.py中,将你的自定义认证后端添加到AUTHENTICATION_BACKENDS列表中。通常,自定义后端应放在默认后端之前,以便优先处理。
# your_project_name/settings.pyAUTHENTICATION_BACKENDS = [ 'your_app_name.backends.EmailBackend', # 你的自定义后端 'django.contrib.auth.backends.ModelBackend', # Django默认的ModelBackend]
5. 定义登录序列化器
登录序列化器用于验证请求中的邮箱和密码数据。
# your_app_name/serializers.pyfrom rest_framework import serializersfrom .models import CustomUserclass 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
注意事项:
继承serializers.Serializer而不是serializers.ModelSerializer更合适,因为你不是在创建或更新CustomUser实例,而只是验证登录凭据。password字段应设置为write_only=True,以防止密码在API响应中泄露。
6. 创建登录API视图
登录API视图将接收客户端发送的邮箱和密码,调用authenticate函数进行认证,并在成功后返回认证令牌。
# your_app_name/views.pyfrom rest_framework.views import APIViewfrom rest_framework.response import Responsefrom rest_framework import statusfrom rest_framework.authtoken.models import Tokenfrom django.contrib.auth import authenticate # 导入Django的authenticate函数from .serializers import LoginSerializerfrom .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)
重要改进:
token, created = Token.objects.get_or_create(user=user): 推荐使用get_or_create来获取或创建用户的认证令牌。这比直接get更健壮,因为如果用户首次登录,可能还没有令牌。authenticate(request, username=email, password=password): Django的authenticate函数会根据AUTHENTICATION_BACKENDS的顺序,尝试所有注册的后端,直到找到一个能够认证成功的后端。
7. URL配置
最后,将登录视图添加到你的urls.py中。
# your_app_name/urls.pyfrom django.urls import pathfrom .views import LoginAPIViewurlpatterns = [ path('login/', LoginAPIView.as_view(), name='login'),]# your_project_name/urls.pyfrom django.contrib import adminfrom django.urls import path, includeurlpatterns = [ 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自定义用户模型实现邮箱登录认证教程的详细内容,更多请关注创想鸟其它相关文章!
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1381550.html
微信扫一扫
支付宝扫一扫