Django跨域会话共享咨询:实现abc.com与xyz.com会话互通
嘿,这个跨域名会话共享的需求我刚好在项目里踩过坑,在Django框架下实现得先区分你的域名类型——是同一顶级域的子域名,还是完全独立的顶级域?两种场景的实现方式差异很大,下面分别给你讲清楚:
场景一:abc.com和xyz.com是同一顶级域的子域名(比如实际是abc.example.com和xyz.example.com)
这种情况可以直接通过Cookie配置+共享会话存储来实现:
1. 配置共享的会话存储
默认的Django数据库会话存储(django.contrib.sessions.backends.db)就可以用,但如果是分布式部署,更推荐用Redis/Memcached这类分布式存储,确保两个站点能访问同一份会话数据。比如用Redis:
先装依赖:
pip install django-redis
然后在两个站点的settings.py里统一配置:
SESSION_ENGINE = "django.contrib.sessions.backends.cache" SESSION_CACHE_ALIAS = "default" CACHES = { "default": { "BACKEND": "django_redis.cache.RedisCache", "LOCATION": "redis://你的-redis地址:6379/1", "OPTIONS": { "CLIENT_CLASS": "django_redis.client.DefaultClient", } } }
如果用数据库存储,确保两个站点连接同一个数据库,能访问django_session表。
2. 配置Cookie跨域参数
在两个站点的settings.py里添加:
# 允许所有子域共享Cookie,注意前面的点 SESSION_COOKIE_DOMAIN = ".example.com" # 允许跨域发送Cookie,必须配合HTTPS SESSION_COOKIE_SAMESITE = "None" # 生产环境必须开启HTTPS,否则浏览器会拒绝SameSite=None的Cookie SESSION_COOKIE_SECURE = True # 统一Cookie名称,默认是sessionid,不用改的话可以忽略 SESSION_COOKIE_NAME = "sessionid"
3. 统一核心配置
两个站点的SECRET_KEY必须完全一致,因为Django用它加密会话数据,不一致的话无法解密对方的会话。
场景二:abc.com和xyz.com是完全独立的顶级域
这种情况浏览器的同源策略会直接阻止跨域共享Cookie,必须用**单点登录(SSO)**方案,这里给你推荐基于Django的落地方式:
1. 选一个站点作为认证中心(比如abc.com)
在abc.com上安装django-oauth-toolkit来实现OAuth2认证:
pip install django-oauth-toolkit
然后配置settings.py:
INSTALLED_APPS = [ # ...其他应用 'oauth2_provider', ] MIDDLEWARE = [ # ...其他中间件 'oauth2_provider.middleware.OAuth2TokenMiddleware', ] AUTHENTICATION_BACKENDS = [ 'oauth2_provider.backends.OAuth2Backend', 'django.contrib.auth.backends.ModelBackend', ] OAUTH2_PROVIDER = { 'SCOPES': {'read': 'Read scope', 'write': 'Write scope', 'groups': 'Access to your groups'}, 'ACCESS_TOKEN_EXPIRE_SECONDS': 3600, # 令牌有效期 }
然后在urls.py里添加OAuth2的路由:
from django.urls import path, include from oauth2_provider.views import AuthorizationView, TokenView, RevokeTokenView urlpatterns = [ # ...其他路由 path('oauth2/', include('oauth2_provider.urls', namespace='oauth2_provider')), ]
2. 在xyz.com上配置OAuth2客户端
安装requests-oauthlib:
pip install requests-oauthlib
然后在xyz.com的settings.py里添加认证中心的配置:
OAUTH2_CLIENT_ID = "你的abc.com上创建的客户端ID" OAUTH2_CLIENT_SECRET = "你的客户端密钥" OAUTH2_AUTHORIZE_URL = "https://abc.com/oauth2/authorize/" OAUTH2_TOKEN_URL = "https://abc.com/oauth2/token/" OAUTH2_USERINFO_URL = "https://abc.com/api/userinfo/" # 你需要在abc.com写一个接口返回用户信息
然后写一个视图来处理跳转认证和获取用户信息:
from django.shortcuts import redirect from django.contrib.auth import login from requests_oauthlib import OAuth2Session def sso_login(request): oauth = OAuth2Session(OAUTH2_CLIENT_ID, redirect_uri="https://xyz.com/sso/callback/") authorization_url, state = oauth.authorization_url(OAUTH2_AUTHORIZE_URL) request.session['oauth_state'] = state return redirect(authorization_url) def sso_callback(request): oauth = OAuth2Session(OAUTH2_CLIENT_ID, state=request.session['oauth_state'], redirect_uri="https://xyz.com/sso/callback/") token = oauth.fetch_token(OAUTH2_TOKEN_URL, client_secret=OAUTH2_CLIENT_SECRET, authorization_response=request.build_absolute_uri()) user_info = oauth.get(OAUTH2_USERINFO_URL).json() # 根据user_info创建或获取本地用户 from django.contrib.auth.models import User user, created = User.objects.get_or_create(username=user_info['username'], defaults={'email': user_info['email']}) login(request, user) return redirect('/')
在xyz.com的urls.py里添加这两个视图的路由。
3. 测试流程
- 用户访问xyz.com,未登录则跳转到abc.com的认证页面;
- 用户在abc.com登录后,授权xyz.com访问用户信息;
- 跳转回xyz.com,自动创建本地会话,实现登录状态共享。
通用注意事项
- 生产环境必须开启HTTPS,否则跨域Cookie和OAuth2都无法正常工作;
- 两个站点的用户模型最好保持一致,避免用户信息同步出现问题;
- 如果用SSO方案,要做好令牌的过期和刷新机制。
内容的提问来源于stack exchange,提问作者Neha Goel
相关产品推荐
相关产品推荐

