Django登录无法识别提交数据:401错误求助
登录401错误排查与修复
核心问题分析
登录返回401的原因主要有两点:
- 自定义用户模型未集成Django认证系统:Django的
authenticate()函数默认只识别继承AbstractBaseUser的用户模型,你的Usuario_aplicacion只是普通Model,导致authenticate返回None。 - 密码哈希方式不匹配:注册用
bcrypt哈希密码,但模型的check_password调用Django自带的check_password,而Django默认哈希器不兼容原生bcrypt格式,同时authenticate也无法识别该哈希密码。
分步修复方案
1. 修改用户模型,集成Django认证系统
将Usuario_aplicacion改为继承AbstractBaseUser和PermissionsMixin,让Django认证系统能识别它:
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager, PermissionsMixin from django.db import models class UsuarioManager(BaseUserManager): def create_user(self, username, email, password=None): if not username: raise ValueError('El usuario debe tener un nombre de usuario') if not email: raise ValueError('El usuario debe tener un email') user = self.model( username=username, email=self.normalize_email(email), ) user.set_password(password) user.save(using=self._db) return user def create_superuser(self, username, email, password): user = self.create_user(username, email, password) user.is_staff = True user.is_superuser = True user.save(using=self._db) return user class Usuario_aplicacion(AbstractBaseUser, PermissionsMixin): username = models.CharField(max_length=100, unique=True) email = models.EmailField(unique=True) is_active = models.BooleanField(default=True) is_staff = models.BooleanField(default=False) objects = UsuarioManager() USERNAME_FIELD = 'username' REQUIRED_FIELDS = ['email'] def __str__(self): return self.username
2. 在settings.py中配置自定义用户模型
添加以下配置,告诉Django使用你的自定义用户模型:
AUTH_USER_MODEL = 'users.Usuario_aplicacion'
3. 修改序列化器,使用Django自带的密码哈希
删除手动用bcrypt哈希的代码,让Django自动处理密码哈希:
from rest_framework import serializers from .models import Usuario_aplicacion class UsuarioSerializer(serializers.ModelSerializer): class Meta: model = Usuario_aplicacion fields = ['username', 'password', 'email'] extra_kwargs = {'password': {'write_only': True}} def create(self, validated_data): user = Usuario_aplicacion.objects.create_user( username=validated_data['username'], email=validated_data['email'], password=validated_data['password'] ) return user
4. 简化登录视图,利用Django认证系统
不需要手动查询用户后再调用authenticate,直接用authenticate即可:
from django.contrib.auth import authenticate, login from rest_framework.decorators import api_view, permission_classes from rest_framework.response import Response from rest_framework.permissions import AllowAny @api_view(['POST']) @permission_classes([AllowAny]) def login_user(request): username = request.data.get('username') password = request.data.get('password') user = authenticate(request, username=username, password=password) if user is not None: login(request, user) return Response({'success': True}) return Response({'success': False}, status=401)
注:去掉
csrf_exempt,改用permission_classes([AllowAny])更安全,后续React端需要正确传递CSRF token。
5. 修复React端CSRF Token问题
React中的{% csrf_token %}无效,因为模板标签只在Django模板中生效。修改React代码,让axios自动携带CSRF cookie:
import React, { useState } from 'react'; import axios from 'axios'; // 配置axios自动携带CSRF token axios.defaults.withCredentials = true; function LoginForm() { const [username, setUsername] = useState(''); const [password, setPassword] = useState(''); const [message, setMessage] = useState(''); const handleSubmit = (event) => { event.preventDefault(); axios.post('http://127.0.0.1:8000/apiusers/login/', { username: username, password: password, }) .then(response => { if (response.data.success) { setMessage('Login successful'); } else { setMessage('Login failed'); } }) .catch(error => { setMessage('Login failed'); }); }; return ( <form onSubmit={handleSubmit}> <label> Username: <input type="text" value={username} onChange={(e) => setUsername(e.target.value)} /> </label> <label> Password: <input type="password" value={password} onChange={(e) => setPassword(e.target.value)} /> </label> <button type="submit">Login</button> {message && <div>{message}</div>} </form> ); } export default LoginForm;
同时需要在Django的settings.py中配置CORS,允许前端域名访问:
INSTALLED_APPS = [ # ... 'corsheaders', ] MIDDLEWARE = [ 'corsheaders.middleware.CorsMiddleware', 'django.middleware.common.CommonMiddleware', # ... ] CORS_ALLOW_CREDENTIALS = True CORS_ALLOWED_ORIGINS = [ 'http://localhost:3000', # 你的React前端地址 ]
注意事项
- 修改用户模型后,需要重新生成迁移文件并执行迁移:
python manage.py makemigrations python manage.py migrate - 之前注册的用户密码是用bcrypt哈希的,无法被新系统识别,需要重新注册用户或者手动更新密码为Django兼容的哈希格式。
内容的提问来源于stack exchange,提问作者Raúl Vaquerizo Tortosa
相关产品推荐
相关产品推荐

