使用Django REST Framework登录遇KeyError: 'user'及最优实现咨询
嘿,咱们来解决你的问题,顺便聊聊DRF实现登录的最优方案~
先搞定你的
KeyError: 'user'问题 你遇到这个错误的核心原因是:当序列化器验证失败(比如邮箱/密码错误)时,没有往data里注入user键,但视图里依然尝试获取它。咱们来修改序列化器,把这个坑填上:
修复后的序列化器代码
from rest_framework import serializers from django.contrib.auth import authenticate from django.contrib.auth.models import User class LoginSerializers(serializers.Serializer): email = serializers.CharField(max_length=255) password = serializers.CharField(max_length=128, write_only=True) def validate(self, data): email = data.get('email', None) password = data.get('password', None) # 先检查邮箱和密码是否为空 if not email or not password: raise serializers.ValidationError("邮箱和密码均不能为空") # 调用Django自带的认证方法验证用户 user = authenticate(username=email, password=password) # 认证失败直接抛出错误,避免后续代码走到取user的步骤 if not user: raise serializers.ValidationError("邮箱或密码不正确") # 可选:确保用户是活跃状态,防止禁用用户登录 if not user.is_active: raise serializers.ValidationError("该用户已被禁用") data['user'] = user return data
修复要点:
- 去掉了多余的
Meta类(你用的是Serializer而非ModelSerializer,指定model没有实际作用) - 添加空值检查,避免
authenticate传入无效参数 - 认证失败时主动抛出
ValidationError,让serializer.is_valid(raise_exception=True)直接返回错误响应 - 增加用户活跃状态校验(可选但推荐)
修改后你的视图类就能正常获取serializer.validated_data['user'],不会再出现KeyError了。
DRF实现登录的最优方案
其实DRF已经提供了成熟的登录解决方案,不用从零手写APIView。根据项目规模和需求,推荐两种主流方案:
方案1:DRF自带Token认证(适合小型项目)
这是最轻量化的实现,DRF内置了全套工具,几步就能搞定:
步骤1:配置项目
在settings.py中添加:
INSTALLED_APPS = [ # 其他已安装应用 'rest_framework.authtoken', ] REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': [ 'rest_framework.authentication.TokenAuthentication', ], }
步骤2:添加路由
在urls.py中引入内置登录视图:
from rest_framework.authtoken.views import obtain_auth_token urlpatterns = [ # 其他路由 path('api/login/', obtain_auth_token, name='api-login'), ]
这个视图默认接收username和password参数,返回token。如果需要自定义返回内容(比如用户ID、邮箱),可以继承ObtainAuthToken重写:
from rest_framework.authtoken.views import ObtainAuthToken from rest_framework.response import Response from rest_framework import status class CustomAuthToken(ObtainAuthToken): def post(self, request, *args, **kwargs): serializer = self.serializer_class(data=request.data, context={'request': request}) serializer.is_valid(raise_exception=True) user = serializer.validated_data['user'] token, created = Token.objects.get_or_create(user=user) return Response({ 'token': token.key, 'user_id': user.pk, 'email': user.email }, status=status.HTTP_200_OK)
然后把路由换成这个自定义视图即可。
方案2:JWT认证(适合前后端分离/大型项目)
JWT(JSON Web Token)是更安全灵活的方案,支持token过期和刷新机制,推荐用djangorestframework-simplejwt库实现:
步骤1:安装依赖
pip install djangorestframework-simplejwt
步骤2:配置项目
在settings.py中添加:
REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': ( 'rest_framework_simplejwt.authentication.JWTAuthentication', ) } # 可选:自定义token有效期 from datetime import timedelta SIMPLE_JWT = { 'ACCESS_TOKEN_LIFETIME': timedelta(minutes=30), # 访问令牌有效期30分钟 'REFRESH_TOKEN_LIFETIME': timedelta(days=1), # 刷新令牌有效期1天 }
步骤3:添加路由
在urls.py中引入JWT相关视图:
from rest_framework_simplejwt.views import ( TokenObtainPairView, TokenRefreshView, ) urlpatterns = [ # 其他路由 path('api/token/', TokenObtainPairView.as_view(), name='token_obtain_pair'), # 获取token path('api/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'), # 刷新token ]
api/token/:接收username和password,返回access(访问令牌)和refresh(刷新令牌)api/token/refresh/:接收refresh令牌,返回新的access令牌
方案对比
- Token认证:实现简单,适合小型、对安全性要求不高的项目;缺点是token无过期时间,除非手动删除否则一直有效。
- JWT认证:支持过期、刷新机制,安全性更高,适合前后端分离、大型项目;缺点是配置稍复杂,但功能更全面。
内容的提问来源于stack exchange,提问作者unknown
相关产品推荐
相关产品推荐

