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

如何在单个项目中实现两个React应用间带Token的跨域跳转?

跨域React应用间传递Token的解决方案(结合Django后端)

针对你两个独立React应用(app1:3000、app2:3001)跨域传递登录token的需求,以下是几种可行方案,结合Django后端给出具体实现:

1. URL参数传递(快速实现,适合测试/低敏感场景)

登录成功后,app1直接把token拼在跳转URL的查询参数中,app2解析后使用。

  • app1跳转代码:
// 登录成功拿到token后
const accessToken = 'xxx';
const refreshToken = 'yyy';
window.location.href = `http://localhost:3001?access_token=${accessToken}&refresh_token=${refreshToken}`;
  • app2解析参数:
import { useLocation } from 'react-router-dom';

function App() {
  const location = useLocation();
  const params = new URLSearchParams(location.search);
  const accessToken = params.get('access_token');
  const refreshToken = params.get('refresh_token');
  
  // 拿到token后存入app2的localStorage或直接使用
  if (accessToken) {
    localStorage.setItem('access_token', accessToken);
  }
  // ...后续逻辑
}
  • 注意事项:token会暴露在浏览器地址栏、历史记录和服务器日志中,仅适合非敏感场景,建议给token设置较短的有效期,Django后端要严格校验token的合法性。

2. 共享Cookie(适合同主域跨端口/子域名场景)

利用浏览器Cookie的跨域共享特性,让两个应用共享存储在Cookie中的token,需要配合Django的CORS配置。

  • Django配置:
    1. 确保安装并启用django-cors-headers,在settings.py中设置:
    INSTALLED_APPS = [
        # ...其他应用
        'corsheaders',
    ]
    
    MIDDLEWARE = [
        'corsheaders.middleware.CorsMiddleware',
        'django.middleware.common.CommonMiddleware',
        # ...其他中间件
    ]
    
    # 允许的跨域源
    CORS_ALLOWED_ORIGINS = [
        "http://localhost:3000",
        "http://localhost:3001",
    ]
    
    # 允许携带Cookie
    CORS_ALLOW_CREDENTIALS = True
    
    # 配置Cookie属性(生产环境必须设置Secure=True,开发环境可暂时关闭)
    SESSION_COOKIE_SAMESITE = 'None'
    SESSION_COOKIE_SECURE = False  # 生产改为True
    CSRF_COOKIE_SAMESITE = 'None'
    CSRF_COOKIE_SECURE = False  # 生产改为True
    
    1. 登录接口返回时,把token存入Cookie:
    from django.http import JsonResponse
    
    def login(request):
        # 验证用户逻辑...
        access_token = generate_access_token(user)
        refresh_token = generate_refresh_token(user)
        
        response = JsonResponse({'status': 'success'})
        # 设置Cookie,max_age根据需求调整
        response.set_cookie('access_token', access_token, max_age=3600, httponly=True, samesite='None', secure=False)
        response.set_cookie('refresh_token', refresh_token, max_age=86400, httponly=True, samesite='None', secure=False)
        return response
    
  • React配置:
    app1和app2的所有后端请求都要携带withCredentials: true:
    // app1登录请求
    fetch('http://your-django-api/login', {
      method: 'POST',
      credentials: 'include', // 携带Cookie
      body: JSON.stringify({username, password}),
      headers: {'Content-Type': 'application/json'}
    })
    
    // app2请求后端接口
    fetch('http://your-django-api/protected-resource', {
      credentials: 'include', // 自动携带共享的Cookie
      headers: {'Authorization': `Bearer ${accessToken}`} // 或者直接让Django从Cookie取token
    })
    
  • 注意事项:localhost不同端口属于不同源,需确保浏览器允许跨域Cookie(现代浏览器默认支持SameSite=None; Secure的跨域Cookie),生产环境必须开启Secure属性(仅HTTPS传输)。

3. 授权码模式(最高安全级别,适合生产环境)

参考OAuth2的授权码流程,用短期有效授权码代替直接传递token,避免token泄露风险。

  • 流程:
    1. app1登录成功后,向Django后端请求一个临时授权码(有效期5分钟左右)
    2. app1携带授权码跳转到app2
    3. app2拿到授权码后,向Django后端请求换取正式的access/refresh token
    4. 后端验证授权码有效后,返回token给app2,同时销毁授权码
  • Django实现:
    1. 新建临时授权码模型:
    from django.db import models
    from django.contrib.auth.models import User
    from datetime import datetime, timedelta
    
    class AuthCode(models.Model):
        user = models.ForeignKey(User, on_delete=models.CASCADE)
        code = models.CharField(max_length=64, unique=True)
        expires_at = models.DateTimeField()
        
        @classmethod
        def generate_code(cls, user):
            import uuid
            code = uuid.uuid4().hex
            expires_at = datetime.now() + timedelta(minutes=5)
            cls.objects.create(user=user, code=code, expires_at=expires_at)
            return code
        
        @classmethod
        def validate_code(cls, code):
            try:
                auth_code = cls.objects.get(code=code, expires_at__gt=datetime.now())
                auth_code.delete()  # 验证后立即销毁
                return auth_code.user
            except cls.DoesNotExist:
                return None
    
    1. 提供获取授权码和换取token的接口:
    def get_auth_code(request):
        # 确保用户已登录(可通过session或token验证)
        user = request.user
        if user.is_authenticated:
            code = AuthCode.generate_code(user)
            return JsonResponse({'code': code})
        return JsonResponse({'error': 'Unauthorized'}, status=401)
    
    def exchange_token(request):
        code = request.GET.get('code')
        user = AuthCode.validate_code(code)
        if user:
            access_token = generate_access_token(user)
            refresh_token = generate_refresh_token(user)
            return JsonResponse({'access_token': access_token, 'refresh_token': refresh_token})
        return JsonResponse({'error': 'Invalid or expired code'}, status=400)
    
  • React实现:
    app1获取授权码后跳转:
    // 登录成功后请求授权码
    fetch('http://your-django-api/get-auth-code', {credentials: 'include'})
      .then(res => res.json())
      .then(data => {
        window.location.href = `http://localhost:3001?code=${data.code}`;
      })
    
    app2换取token:
    import { useLocation } from 'react-router-dom';
    
    function App() {
      const location = useLocation();
      const params = new URLSearchParams(location.search);
      const code = params.get('code');
      
      if (code) {
        fetch(`http://your-django-api/exchange-token?code=${code}`)
          .then(res => res.json())
          .then(data => {
            if (data.access_token) {
              localStorage.setItem('access_token', data.access_token);
              localStorage.setItem('refresh_token', data.refresh_token);
            }
          })
      }
      // ...后续逻辑
    }
    
  • 优势:授权码短期有效且一次性使用,即使泄露也无法重复获取token,安全性远高于前两种方案,适合生产环境。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 14:36:02