Django Token认证异常:凭证正确却无法生成Token并返回错误
问题排查与解决思路
1. 确认自定义User模型的USERNAME_FIELD配置
如果你的User模型是自定义的(非Django默认用户模型),必须在模型类中指定USERNAME_FIELD = 'email',让Django认证系统将邮箱作为用户唯一标识:
class User(AbstractBaseUser, PermissionsMixin): email = models.EmailField(unique=True) # 其他自定义字段... USERNAME_FIELD = 'email' # 关键配置 REQUIRED_FIELDS = [] # 根据业务需求添加必填字段
若缺少该配置,默认的ModelBackend会尝试用username字段认证,你传入的email参数无法被识别,直接导致authenticate()返回None。
2. 检查认证后端配置
确保settings.py中的AUTHENTICATION_BACKENDS包含支持邮箱认证的后端:
- 若已设置
USERNAME_FIELD = 'email',保留默认后端即可:
AUTHENTICATION_BACKENDS = [ 'django.contrib.auth.backends.ModelBackend', ]
- 若未修改
USERNAME_FIELD,需自定义认证后端支持邮箱登录:
# 在你的app下创建backends.py from django.contrib.auth.backends import ModelBackend from django.contrib.auth import get_user_model from django.db.models import Q UserModel = get_user_model() class EmailBackend(ModelBackend): def authenticate(self, request, username=None, password=None, **kwargs): try: user = UserModel.objects.get(Q(email=username)) except UserModel.DoesNotExist: UserModel().set_password(password) return None except UserModel.MultipleObjectsReturned: user = UserModel.objects.filter(Q(email=username)).first() if user.check_password(password) and self.user_can_authenticate(user): return user
然后在settings.py中配置:
AUTHENTICATION_BACKENDS = [ 'your_app.backends.EmailBackend', 'django.contrib.auth.backends.ModelBackend', ]
3. 验证密码存储合法性
确认数据库中用户密码是哈希值而非明文:
- 进入Django Shell:
python manage.py shell - 执行验证:
from your_app.models import User user = User.objects.get(email='测试邮箱') print(user.check_password('测试密码')) # 返回True才正常
若返回False,说明创建用户时未正确调用set_password,需检查UserSerializer的create方法是否被正确执行。
4. 调整LoginAPIView逻辑顺序
先验证请求数据合法性,再执行认证操作,同时给authenticate传入request参数:
class LoginAPIView(views.APIView): def post(self, request): serializer = LoginSerializer(data=request.data) if serializer.is_valid(): email = serializer.validated_data["email"] password = serializer.validated_data["password"] # 若用自定义EmailBackend,这里username参数传邮箱;若设置了USERNAME_FIELD='email',也可直接用email参数 user = authenticate(request=request, username=email, password=password) if user is not None: token, created = Token.objects.get_or_create(user=user) return Response({ 'data': serializer.data, 'token': token.key }) else: return Response({ 'errors': 'Invalid email or password.' }, status=400) else: return Response(serializer.errors, status=400)
5. 完善LoginSerializer字段配置
给password字段添加write_only=True,避免密码哈希值在响应中返回:
class LoginSerializer(serializers.ModelSerializer): password = serializers.CharField(write_only=True) class Meta: model = User fields = ['email', 'password']
内容的提问来源于stack exchange,提问作者Abdurrafay Saqlain
相关产品推荐
相关产品推荐

