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

React如何对接Django后端实现用户登录、状态维护与登出

Django + React 前后端分离登录/登出实现方案

核心逻辑说明

Django原生登录的底层逻辑非常简单,整个流程和模板渲染模式没有本质区别,核心只有三步:

  • 校验传入的用户名、密码是否匹配数据库用户
  • 校验通过后生成服务端session,将sessionid写入响应头的Set-Cookie字段
  • 后续所有携带合法sessionid的请求,Django中间件会自动解析出对应用户,直接通过request.user获取用户实例、request.user.is_authenticated判断登录状态,不需要额外开发
    前后端分离模式下不需要替换成JWT等其他方案,只需要处理跨域场景下的Cookie携带、CSRF校验两个问题即可,完全复用Django原生的认证能力。

后端(Django)配置

1. 安装并配置跨域依赖

先安装django-cors-headers处理跨域请求:

pip install django-cors-headers

修改settings.py配置:

INSTALLED_APPS = [
    # 原有应用配置保留
    'corsheaders',
]

MIDDLEWARE = [
    # 该中间件必须放在最顶部,优先于CommonMiddleware
    'corsheaders.middleware.CorsMiddleware',
    'django.middleware.common.CommonMiddleware',
    # 原有其他中间件保留
]

# 允许前端本地开发地址跨域
CORS_ALLOWED_ORIGINS = [
    "http://127.0.0.1:3000",
    "http://localhost:3000",
]
# 允许跨域请求携带Cookie
CORS_ALLOW_CREDENTIALS = True

# 配置CSRF信任的前端源,避免POST请求被CSRF防护拦截
CSRF_TRUSTED_ORIGINS = [
    "http://127.0.0.1:3000",
    "http://localhost:3000",
]

2. 编写认证相关接口

废弃原有模板渲染的LoginView,直接编写返回JSON的接口:

# users/views.py
from django.contrib.auth import authenticate, login, logout
from django.http import JsonResponse
from django.middleware.csrf import get_token
from django.views.decorators.csrf import ensure_csrf_cookie
import json

# 获取CSRF Token接口,前端初始化时调用
@ensure_csrf_cookie
def get_csrf_token(request):
    return JsonResponse({"csrfToken": get_token(request)})

# 登录接口
def login_api(request):
    if request.method != "POST":
        return JsonResponse({"code": 405, "msg": "请求方法不允许"}, status=405)
    request_data = json.loads(request.body)
    username = request_data.get("username", "").strip()
    password = request_data.get("password", "")
    
    # 校验账号密码
    user = authenticate(request, username=username, password=password)
    if not user:
        return JsonResponse({"code": 400, "msg": "用户名或密码错误"}, status=400)
    
    # 调用Django原生login方法,写入session
    login(request, user)
    # 登录成功直接返回用户基本信息,sessionid会自动通过Set-Cookie写入浏览器
    return JsonResponse({
        "code": 200,
        "msg": "登录成功",
        "data": {
            "id": user.id,
            "username": user.username
        }
    })

# 登出接口
def logout_api(request):
    logout(request)
    return JsonResponse({"code": 200, "msg": "登出成功"})

# 获取当前登录用户信息接口
def get_current_user(request):
    if not request.user.is_authenticated:
        return JsonResponse({"code": 401, "msg": "未登录"}, status=401)
    return JsonResponse({
        "code": 200,
        "data": {
            "id": request.user.id,
            "username": request.user.username
        }
    })

3. 配置路由

# users/urls.py
from django.urls import path
from . import views

urlpatterns = [
    path('api/csrf/', views.get_csrf_token, name='api-csrf'),
    path('api/login/', views.login_api, name='api-login'),
    path('api/logout/', views.logout_api, name='api-logout'),
    path('api/user/info/', views.get_current_user, name='api-user-info'),
    # 原有其他业务接口保留
]

前端(React)对接

所有请求必须开启withCredentials配置,否则跨域场景下Cookie不会被携带,后端无法识别登录状态。

1. 封装请求实例

以axios为例:

// utils/request.js
import axios from 'axios'

const service = axios.create({
  baseURL: 'http://127.0.0.1:8000',
  // 核心配置:跨域请求携带Cookie
  withCredentials: true
})

// 请求拦截器自动注入CSRF Token
service.interceptors.request.use(config => {
  const csrfToken = document.cookie
    .split('; ')
    .find(row => row.startsWith('csrftoken='))
    ?.split('=')[1]
  if (csrfToken) {
    config.headers['X-CSRFToken'] = csrfToken
  }
  return config
})

// 响应拦截器统一处理未登录场景
service.interceptors.response.use(
  response => response.data,
  error => {
    if (error.response.status === 401) {
      // 未登录时清空用户状态,跳转登录页
      window.location.href = '/login'
    }
    return Promise.reject(error)
  }
)

export default service

2. 应用初始化校验登录状态

应用加载时先获取CSRF Cookie,再拉取当前用户信息,判断是否已登录:

// App.jsx
import { useEffect, useState } from 'react'
import request from './utils/request'
import LoginPage from './pages/Login'
import HomePage from './pages/Home'

function App() {
  const [user, setUser] = useState(null)
  const [loading, setLoading] = useState(true)

  useEffect(() => {
    const initAuth = async () => {
      try {
        // 初始化CSRF Cookie
        await request.get('/api/csrf/')
        // 拉取当前登录用户信息
        const res = await request.get('/api/user/info/')
        setUser(res.data)
      } catch (err) {
        setUser(null)
      } finally {
        setLoading(false)
      }
    }
    initAuth()
  }, [])

  if (loading) return <div>加载中...</div>

  return user ? <HomePage user={user} setUser={setUser} /> : <LoginPage setUser={setUser} />
}

export default App

3. 登录页实现

// pages/Login.jsx
import { useState } from 'react'
import request from '../utils/request'

export default function LoginPage({ setUser }) {
  const [formData, setFormData] = useState({username: '', password: ''})
  const [errorMsg, setErrorMsg] = useState('')

  const handleSubmit = async (e) => {
    e.preventDefault()
    setErrorMsg('')
    try {
      const res = await request.post('/api/login/', formData)
      // 登录成功后将用户信息存入全局状态
      setUser(res.data)
    } catch (err) {
      setErrorMsg(err.response.data.msg || '登录失败,请重试')
    }
  }

  return (
    <form onSubmit={handleSubmit}>
      {errorMsg && <p className="error">{errorMsg}</p>}
      <div>
        <label>用户名</label>
        <input
          type="text"
          value={formData.username}
          onChange={e => setFormData({...formData, username: e.target.value})}
        />
      </div>
      <div>
        <label>密码</label>
        <input
          type="password"
          value={formData.password}
          onChange={e => setFormData({...formData, password: e.target.value})}
        />
      </div>
      <button type="submit">登录</button>
    </form>
  )
}

4. 登出功能实现

在需要触发登出的位置添加按钮,调用登出接口即可:

// 组件内登出逻辑
const handleLogout = async () => {
  await request.post('/api/logout/')
  setUser(null)
}

常见问题说明

  • 密码明文传输问题:本地开发阶段无需额外处理,上线时给前后端配置HTTPS即可,传输层会自动加密所有请求数据。自行在前端做密码加密没有实际防护意义,中间人截获加密后的密文依然可以重放请求,HTTPS是成本最低、最可靠的方案。
  • 登录状态维护:不需要额外在localStorage等位置存储令牌,sessionid会由浏览器自动保存在Cookie中,只要请求开启了withCredentials,后端会自动识别用户身份。前端只需要把用户信息存在全局状态(Context、Redux、Zustand均可),页面刷新时重新调用/api/user/info拉取用户信息即可。
  • 接口权限控制:后端视图可以直接复用Django自带的@login_required装饰器,未登录的请求会自动返回错误,前端在响应拦截器统一处理跳转逻辑即可,和原有模板模式的权限逻辑完全一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 15:21:25