Identity Server 4与Sustainsys SAML2误将非CORS请求判定为CORS请求并拒绝
我之前也碰到过完全一致的场景——用Identity Server 4集成AspNetIdentity,对接Sustainsys SAML2做外部登录,本地账号正常,但在关联SAML账号到本地账号时,遇到了非CORS请求被误判拦截的问题。下面是几个我验证过的有效解决方案:
1. 修正Sustainsys SAML2的回调配置
首先要确认SAML2的回调地址没有被错误标记为跨域请求。在Sustainsys的配置中,务必保证CallbackPath是Identity Server的本地端点,绝对不要把这个本地回调地址加到Identity Server的AllowedCorsOrigins里(因为这是服务内部请求,根本不需要CORS配置)。
示例配置代码:
services.AddSaml2(options => { options.SPOptions.EntityId = new EntityId("https://identity.domain.com"); options.IdentityProviders.Add( new IdentityProvider( new EntityId("https://your-saml-provider.com/metadata"), options.SPOptions) { LoadMetadata = true, // 回调地址必须是Identity Server自身的端点,不要填外部域名 SignOnUrl = "https://identity.domain.com/signin-saml2" }); });
2. 调整Identity Server的CORS策略
Identity Server默认的CORS处理逻辑偶尔会把内部请求误判为跨域。你可以自定义CORS策略,明确排除SAML回调端点:
services.AddCors(options => { options.AddPolicy("IdentityServerCors", policy => { policy.WithOrigins("https://your-real-client-domains.com") // 只添加真正的客户端域名 .AllowAnyHeader() .AllowAnyMethod() .WithExposedHeaders("Location") // 排除SAML回调端点,避免被CORS策略拦截 .AddExclusionFromPolicy(ctx => ctx.Request.Path.StartsWithSegments("/signin-saml2")); }); }); // 让Identity Server使用这个自定义CORS策略 services.AddIdentityServer() .AddAspNetIdentity<ApplicationUser>() .AddCorsPolicyService<DefaultCorsPolicyService>() .AddSaml2();
3. 修复Sustainsys的请求上下文判定
有时候Sustainsys内部会错误识别请求来源,你可以通过自定义Saml2AuthenticationHandler强制修正这个判定:
public class CustomSaml2AuthenticationHandler : Saml2AuthenticationHandler { public CustomSaml2AuthenticationHandler(IOptionsMonitor<Saml2Options> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) : base(options, logger, encoder, clock) { } protected override async Task<AuthenticateResult> HandleRequestAsync() { // 强制标记当前请求为非CORS请求 Context.Items["__CORS_REQUEST__"] = false; return await base.HandleRequestAsync(); } }
然后在Startup中替换默认的Handler:
services.AddAuthentication() .AddSaml2(options => { /* 你的SAML配置 */ }) .AddScheme<Saml2Options, CustomSaml2AuthenticationHandler>(Saml2Defaults.AuthenticationScheme, "SAML2");
4. 验证关联流程的请求方式
最后检查你的账号关联页面(/Manage/ExternalLogins)的交互逻辑:确保触发SAML登录的是页面跳转或表单提交,而不是AJAX请求——AJAX会触发浏览器的CORS预检,但账号关联流程本质是页面跳转,完全不需要用AJAX发起请求。
总结一下,最常见的根源是SAML回调地址被错误加入CORS允许列表,或者Identity Server的CORS策略没有排除内部端点。建议先从配置检查入手,再逐步排查代码层面的问题。
内容的提问来源于stack exchange,提问作者Fanetic

