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

React前端通过Google OAuth2重定向后无法接收Django后端API令牌的问题及完整集成流程求助

React前端通过Google OAuth2重定向后无法接收Django后端API令牌的问题及完整集成流程求助

我太懂你现在的困扰了——Google OAuth的登录流程明明走通了,用户信息也乖乖存进数据库了,可前端就是拿不到后端生成的access/refresh令牌,没法做后续的API请求对吧?别慌,咱们一步步把这个闭环补全,把令牌稳稳交到React手里。

首先得理清核心逻辑:你现在的流程只完成了「Google认证用户→Django关联/创建用户」这一步,而drf-social-oauth2生成的Django自有令牌,需要通过convert-token接口主动换取,不是默认重定向就会给的。下面是完整的集成流程:

一、先把关键前置准备做扎实

  1. 在Django后台创建OAuth2应用
    进入Django admin,找到oauth2_provider下的Application,新建一个应用:

    • 类型选「Public」(因为React是单页应用,没法安全存client_secret)
    • 重定向URI填你的React域名(比如http://127.0.0.1:5173/login-success)
      保存后拿到的Client ID要记下来,后面前端要用到。
  2. 配置CORS避免跨域坑
    安装django-cors-headers,然后在settings里配置:

    INSTALLED_APPS = [
        ...
        'corsheaders',
        ...
    ]
    
    MIDDLEWARE = [
        'corsheaders.middleware.CorsMiddleware',  # 放最前面
        ...
    ]
    
    CORS_ALLOWED_ORIGINS = [
        "http://127.0.0.1:5173",
    ]
    

二、完整流程:从Google登录到React拿到令牌

步骤1:React引导用户到Django的Google登录地址

在React的登录按钮里,跳转到你配置的Django OAuth地址:

const handleGoogleLogin = () => {
  window.location.href = "http://localhost:8000/api/v1/auth/login/google-oauth2/";
};

步骤2:React处理Google重定向后的授权码

用户授权后,Google会把用户重定向回你的React页面(就是你设置的LOGIN_REDIRECT_URL),此时URL里会带有code和state参数。我们要提取这两个参数,调用convert-token接口换Django令牌:

// 在React的登录回调页面(比如/login-success)
import { useEffect, useNavigate } from 'react';
import axios from 'axios';

const LoginSuccess = () => {
  const navigate = useNavigate();

  useEffect(() => {
    const searchParams = new URLSearchParams(window.location.search);
    const code = searchParams.get('code');
    const state = searchParams.get('state');

    if (code) {
      exchangeCodeForTokens(code, state);
    }
  }, []);

  const exchangeCodeForTokens = async (code, state) => {
    try {
      const res = await axios.post(
        'http://localhost:8000/api/v1/auth/token/convert-token/',
        {
          grant_type: 'convert_token',
          client_id: '你刚才在Django admin拿到的Client ID',
          backend: 'google-oauth2',
          token: code,
          state: state // 带上验证安全性
        }
      );

      // 拿到Django生成的令牌
      const { access_token, refresh_token, expires_in } = res.data;

      // 把令牌存在sessionStorage(比localStorage更安全,避免XSS)
      sessionStorage.setItem('access_token', access_token);
      sessionStorage.setItem('refresh_token', refresh_token);

      // 跳转到应用主页
      navigate('/');
    } catch (err) {
      console.error('换令牌失败:', err);
      alert('登录出错,请重试');
      navigate('/login');
    }
  };

  return <div>登录中...</div>;
};

export default LoginSuccess;

步骤3:React用令牌调用认证API

后续请求需要认证的接口时,在请求头里带上Bearer令牌:

const fetchUserProfile = async () => {
  const accessToken = sessionStorage.getItem('access_token');
  try {
    const res = await axios.get('http://localhost:8000/api/v1/user/profile/', {
      headers: {
        Authorization: `Bearer ${accessToken}`
      }
    });
    console.log('用户信息:', res.data);
  } catch (err) {
    // 令牌过期的话,用refresh_token刷新
    if (err.response.status === 401) {
      await refreshAccessToken();
      fetchUserProfile(); // 刷新后重新请求
    } else {
      console.error('请求失败:', err);
      navigate('/login');
    }
  }
};

// 刷新令牌的函数
const refreshAccessToken = async () => {
  const refreshToken = sessionStorage.getItem('refresh_token');
  try {
    const res = await axios.post(
      'http://localhost:8000/api/v1/auth/token/refresh-token/',
      {
        grant_type: 'refresh_token',
        client_id: '你的Django Client ID',
        refresh_token: refreshToken
      }
    );
    sessionStorage.setItem('access_token', res.data.access_token);
  } catch (err) {
    console.error('刷新令牌失败:', err);
    navigate('/login');
  }
};

三、可选优化:让Django直接把令牌带回React(适合简单场景)

如果你不想在前端处理code,可以修改Django的认证完成视图,重定向时把令牌放在URL的hash片段里(避免参数被服务器记录):

  1. 在Django里写一个自定义的complete视图:
from social_django.views import complete
from drf_social_oauth2.utils import generate_token
from django.http import HttpResponseRedirect
from django.conf import settings

def custom_google_complete(request, backend):
    # 先完成Google认证流程
    response = complete(request, backend)
    if request.user.is_authenticated:
        # 生成Django的OAuth令牌
        token_obj = generate_token(request.user)
        # 把令牌放在hash里重定向回React
        redirect_url = (
            f"{settings.LOGIN_REDIRECT_URL}#"
            f"access_token={token_obj.access_token}&"
            f"refresh_token={token_obj.refresh_token}&"
            f"expires_in={token_obj.expires_in}"
        )
        return HttpResponseRedirect(redirect_url)
    return response
  1. 修改URL配置,替换原有的complete路由:
# 替换原来的social_django.urls中的complete路由
path(
    "api/v1/auth/complete/google-oauth2/",
    custom_google_complete,
    kwargs={"backend": "google-oauth2"},
    name="google-complete"
),
  1. React端提取hash里的令牌:
useEffect(() => {
  const hashParams = new URLSearchParams(window.location.hash.slice(1));
  const accessToken = hashParams.get('access_token');
  if (accessToken) {
    sessionStorage.setItem('access_token', accessToken);
    sessionStorage.setItem('refresh_token', hashParams.get('refresh_token'));
    navigate('/');
  }
}, []);

四、关键注意事项

  • 别把client_secret暴露在前端代码里!如果是单页应用,一定要把Django的OAuth应用类型设为「Public」,这样不需要传client_secret。
  • 令牌存储优先用sessionStorage,关闭浏览器就失效,比localStorage更安全;如果要更安全,还可以用HttpOnly Cookie,但需要调整Django的认证配置。
  • 上线前要把所有的本地域名换成生产环境的域名,包括Django的LOGIN_REDIRECT_URL和CORS配置。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.08 14:34:50