如何在单个项目中实现两个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配置:
- 确保安装并启用
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- 登录接口返回时,把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泄露风险。
- 流程:
- app1登录成功后,向Django后端请求一个临时授权码(有效期5分钟左右)
- app1携带授权码跳转到app2
- app2拿到授权码后,向Django后端请求换取正式的access/refresh token
- 后端验证授权码有效后,返回token给app2,同时销毁授权码
- Django实现:
- 新建临时授权码模型:
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- 提供获取授权码和换取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获取授权码后跳转:
app2换取token:// 登录成功后请求授权码 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}`; })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
相关产品推荐
相关产品推荐

