You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django登录无法识别提交数据:401错误求助

登录401错误排查与修复

核心问题分析

登录返回401的原因主要有两点:

  1. 自定义用户模型未集成Django认证系统:Django的authenticate()函数默认只识别继承AbstractBaseUser的用户模型,你的Usuario_aplicacion只是普通Model,导致authenticate返回None。
  2. 密码哈希方式不匹配:注册用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前端地址
]

注意事项

  1. 修改用户模型后,需要重新生成迁移文件并执行迁移:
    python manage.py makemigrations
    python manage.py migrate
    
  2. 之前注册的用户密码是用bcrypt哈希的,无法被新系统识别,需要重新注册用户或者手动更新密码为Django兼容的哈希格式。

内容的提问来源于stack exchange,提问作者Raúl Vaquerizo Tortosa

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 20:03:15