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

Django会话认证异常:登录后get_user接口仍返回匿名用户

问题:Django DRF + React 跨域认证后,get_user接口仍返回AnonymousUser

我用Django + Django REST Framework做后端,React做前端开发项目。调用login_user接口确认用户已认证(user_is_authenticated=true)后,调用get_user接口始终返回false,得到AnonymousUser。前端Axios请求已设置withCredentials: true,Chrome开发者工具也确认生成了session_id,但问题依旧。

前端get_user请求代码

useEffect(() => {
  (async () => {
    axios
      .get(url, {
        withCredentials: true,
      })
      .then((res) => {});
  })();
}, [location]);

后端views.py代码

from django.contrib.auth import authenticate, login, logout
from django.contrib.auth.hashers import make_password
from rest_framework import serializers, status, permissions, status
from rest_framework.decorators import api_view, authentication_classes
from rest_framework.response import Response
from users.serializers import UserSerializer
from django.contrib.auth.models import User


@api_view(['GET'])
def get_user(request):
    print(request.user.is_authenticated)
    return Response(status=status.HTTP_200_OK)


@api_view(['POST'])
def register_user(request):
    match_username = User.objects.all().filter(
        username=request.data['username'])
    match_email = User.objects.all().filter(email=request.data['email'])

    serializer = UserSerializer(data=request.data)
    if serializer.is_valid() and not match_username and not match_email:
        user = User.objects.create(username=serializer.data['username'], password=make_password(
            serializer.data['password']), email=serializer.data['email'])
        user.save()
        send_register_email(
            serializer.data['username'], serializer.data['email'])
        return Response(status=status.HTTP_201_CREATED, data=UserSerializer(user).data)
    else:
        if match_username:
            return Response(status=status.HTTP_400_BAD_REQUEST, data='Username already exists')
        elif match_email:
            return Response(status=status.HTTP_400_BAD_REQUEST, data='Email already exists')
        else:
            return Response(status=status.HTTP_400_BAD_REQUEST, data="Invalid email")


@api_view(['POST'])
def login_user(request):
    username = User.objects.all().filter(username=request.data['username'])

    if not username:
        return Response(status=status.HTTP_400_BAD_REQUEST, data='Username not found')

    user = authenticate(
        username=request.data['username'], password=request.data['password'])

    if user is not None:
        login(request, user)
        return Response(status=status.HTTP_200_OK, data=UserSerializer(user).data)
    else:
        return Response(status=status.HTTP_400_BAD_REQUEST, data='Incorrect password')

后端settings.py(相关配置)

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.sites',
    'django.contrib.staticfiles',
    'rest_framework',
    'rest_framework.authtoken',
    'corsheaders',
    'users',
    'settings',
]

MIDDLEWARE = [
    "corsheaders.middleware.CorsMiddleware",
    "django.middleware.common.CommonMiddleware",
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework.authentication.SessionAuthentication',
    ]
}


PASSWORD_HASHERS = [
    "django.contrib.auth.hashers.PBKDF2PasswordHasher",
    "django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher",
    "django.contrib.auth.hashers.Argon2PasswordHasher",
    "django.contrib.auth.hashers.BCryptSHA256PasswordHasher",
    "django.contrib.auth.hashers.ScryptPasswordHasher",
]

ROOT_URLCONF = 'users.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WSGI_APPLICATION = 'users.wsgi.application'

# CORS配置
CORS_ALLOW_ALL_ORIGINS = True
CORS_ALLOW_CREDENTIALS = True

问题排查与解决方案

1. 给get_user视图显式指定认证类

虽然全局配置了SessionAuthentication,但显式给视图指定认证类能确保会话认证生效:

from rest_framework.decorators import authentication_classes
from rest_framework.authentication import SessionAuthentication

@api_view(['GET'])
@authentication_classes([SessionAuthentication])
def get_user(request):
    print(request.user.is_authenticated)
    return Response({"is_authenticated": request.user.is_authenticated}, status=status.HTTP_200_OK)

2. 传递CSRF令牌(关键)

跨域场景下,SessionAuthentication需要CSRF令牌验证,否则Django会拒绝会话关联。

前端处理方式:

从Cookie中提取csrftoken,并在请求头中携带:

// 提取CSRF令牌的工具函数
function getCookie(name) {
    let cookieValue = null;
    if (document.cookie && document.cookie !== '') {
        const cookies = document.cookie.split(';');
        for (let i = 0; i < cookies.length; i++) {
            const cookie = cookies[i].trim();
            if (cookie.substring(0, name.length + 1) === (name + '=')) {
                cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                break;
            }
        }
    }
    return cookieValue;
}

useEffect(() => {
  (async () => {
    const csrftoken = getCookie('csrftoken');
    axios
      .get(url, {
        withCredentials: true,
        headers: {
          'X-CSRFToken': csrftoken
        }
      })
      .then((res) => {
        console.log(res.data.is_authenticated);
      });
  })();
}, [location]);

临时排查方案(不推荐生产使用):

给get_user视图豁免CSRF检查,仅用于验证会话是否正常:

from django.views.decorators.csrf import csrf_exempt

@api_view(['GET'])
@csrf_exempt
def get_user(request):
    print(request.user.is_authenticated)
    return Response({"is_authenticated": request.user.is_authenticated}, status=status.HTTP_200_OK)

3. 调整Session Cookie属性(本地开发)

如果是本地跨域开发,浏览器可能限制Cookie传递,在settings.py中添加:

SESSION_COOKIE_SAMESITE = 'Lax'  # 跨域场景可设为'None',但需配合HTTPS
SESSION_COOKIE_SECURE = False  # 本地开发设为False,生产环境必须设为True

内容的提问来源于stack exchange,提问作者dice

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 22:54:53