MSAL React SPA对接Django RESTful API的SAML SSO登录验证方案咨询
SAML SSO + MSAL React + Django 集成验证方案
1. 确认用户在IDP完成登录的安全实现
- 不要信任前端提交的登录状态声明,所有身份验证逻辑必须在后端执行。
- 前端通过MSAL完成IDP登录交互后,只会拿到IDP签发的
access_token,后续所有向后端发起的请求都要在请求头携带Authorization: Bearer <access_token>。 - 只要后端完成
access_token的合法性校验,即可确认用户已在IDP完成合法登录,无需额外做其他交互。
2. 后端无需创建PublicClient实例
你判断的没错,不需要在Python侧创建PublicClient实例:
- PublicClient是前端SPA用于向IDP申请token的工具类,后端的核心职责是验证token有效性,完全不需要模拟前端重新向IDP请求token。
- 也不需要每次验证都向IDP发送请求查询会话状态,
access_token本身是IDP签发的自包含可验证凭证,本地即可完成合法性校验。
3. Django侧token验证实现指引
核心逻辑是校验access_token的签名和核心声明字段,步骤如下:
- 提前从IDP侧获取签名公钥(SAML协议取签名证书、OIDC协议取JWKS公钥集),缓存到Django配置中,不需要每次验证都重新拉取。
- 选用Python的JWT验证库实现校验,推荐用
python-jose或者PyJWT,必须校验以下字段:- 签名合法性:用IDP的公钥验证,确认token没有被篡改
- 过期时间
exp:确认token未超过有效期 - 签发者
iss:必须和你对接的IDP官方签发域名完全一致 - 受众
aud:必须是你在IDP注册的应用客户端ID
- 校验通过后,从token的
sub字段(用户唯一标识)查询你的PostgreSQL数据库中的对应用户,不存在的话可以实现JIT自动创建,之后将用户绑定到请求上下文即可正常处理业务逻辑。
如果有强需求需要同步IDP侧的登出状态(比如用户在IDP侧登出后要立即失效本应用的访问),可以额外实现IDP的SLO(单点登出)回调接口,收到登出请求后将对应用户的当前有效token加入本地黑名单即可。
示例代码(Django 验证中间件)
import jwt from django.conf import settings from django.http import JsonResponse from django.contrib.auth import get_user_model User = get_user_model() class SSOAuthMiddleware: def __init__(self, get_response): self.get_response = get_response def __call__(self, request): # 跳过不需要登录的公开接口 if request.path in settings.PUBLIC_API_PATHS: return self.get_response(request) auth_header = request.META.get('HTTP_AUTHORIZATION') if not auth_header or not auth_header.startswith('Bearer '): return JsonResponse({'error': '缺少有效访问凭证'}, status=401) access_token = auth_header.split(' ')[1] try: payload = jwt.decode( access_token, key=settings.IDP_PUBLIC_KEY, algorithms=["RS256"], issuer=settings.IDP_ISSUER, audience=settings.IDP_CLIENT_ID ) except jwt.InvalidTokenError: return JsonResponse({'error': '访问凭证无效或已过期'}, status=401) # 绑定用户到请求上下文 user, _ = User.objects.get_or_create( sso_uid=payload['sub'], defaults={ 'email': payload.get('email'), 'username': payload.get('preferred_username', payload['sub']) } ) request.user = user return self.get_response(request)
内容的提问来源于stack exchange,提问作者7FigureSwagger
相关产品推荐
相关产品推荐

