Sustainsys Saml2设置HandledResult=true仍生双Cookie,如何仅保留自定义认证Cookie?
问题原因
你设置了options.SignInScheme = "SamlTemp",这会让Sustainsys Saml2自动将认证后的ClaimsPrincipal登录到该指定Scheme,生成对应的Cookie。即使你在AcsCommandResultCreated中设置commandResult.HandledResult = true,库已经在事件触发前完成了登录到SamlTempScheme的操作,所以最终会同时存在库生成的临时Cookie和你自定义的Cookie。
解决方案
方案1:移除SignInScheme配置
直接删除options.SignInScheme = "SamlTemp"这一行,让库不再自动生成任何认证Cookie,完全由你在事件中处理自定义Cookie和响应逻辑。
方案2:拦截更早的事件(AcsCommandCreated)
如果需要保留SignInScheme的其他作用,可改用AcsCommandCreated事件,在库执行登录操作前就拦截整个流程,自行处理认证和Cookie生成,阻止库执行默认逻辑。
修改后的代码示例
方案1的代码调整
options.SPOptions.ModulePath = samlRoutePrefix; // 移除SignInScheme配置,避免库自动生成Cookie options.Notifications.AcsCommandResultCreated = (commandResult, _) => { var httpContext = httpContextAccessor.HttpContext; if (httpContext == null) throw new InvalidOperationException("HttpContext not available — ensure IHttpContextAccessor is registered."); var completeSamlLogin = httpContext.RequestServices.GetRequiredService<ICompleteSamlLogin>(); var authenticationCookieContentMapper = httpContext.RequestServices.GetRequiredService<IAuthenticationCookieContentMapper>(); var relayState = httpContext.Request.Form[SamlConstants.RelayStateKey].ToString(); var claimsPrincipal = commandResult.Principal; var email = ExtractEmailFromClaims(claimsPrincipal); if (string.IsNullOrEmpty(email)) throw new UnauthenticatedException("No email address found in SAML response."); var firstName = claimsPrincipal.FindFirst(ClaimTypes.GivenName)?.Value; var lastName = claimsPrincipal.FindFirst(ClaimTypes.Surname)?.Value; var input = new CompleteSamlLoginInput { RelayState = relayState, Email = email, FirstName = firstName, LastName = lastName }; var loginOutput = completeSamlLogin.Execute(input).Result; var cookieContent = authenticationCookieContentMapper.Map(loginOutput); httpContext.CreateAuthenticationCookieAsync(cookieContent, true).GetAwaiter().GetResult(); commandResult.Headers.Add(SCloudHeaderNames.AntiCsrfToken, cookieContent.AntiCsrfToken.ToString()); // 设置HandledResult为true,告诉库不要处理后续响应 commandResult.HandledResult = true; // 手动处理RelayState重定向(如果需要) if (!string.IsNullOrEmpty(relayState)) { httpContext.Response.Redirect(relayState); } };
方案2的代码示例(使用AcsCommandCreated)
options.SPOptions.ModulePath = samlRoutePrefix; options.SignInScheme = "SamlTemp"; // 保留该配置的话用此方案 options.Notifications.AcsCommandCreated = (command, _) => { var httpContext = httpContextAccessor.HttpContext; if (httpContext == null) throw new InvalidOperationException("HttpContext not available — ensure IHttpContextAccessor is registered."); // 从SAML命令中获取认证后的Principal var samlCommand = command as Saml2SignInCommand; if (samlCommand == null || samlCommand.Principal == null) return; var completeSamlLogin = httpContext.RequestServices.GetRequiredService<ICompleteSamlLogin>(); var authenticationCookieContentMapper = httpContext.RequestServices.GetRequiredService<IAuthenticationCookieContentMapper>(); var relayState = samlCommand.RelayState; var claimsPrincipal = samlCommand.Principal; var email = ExtractEmailFromClaims(claimsPrincipal); if (string.IsNullOrEmpty(email)) throw new UnauthenticatedException("No email address found in SAML response."); var firstName = claimsPrincipal.FindFirst(ClaimTypes.GivenName)?.Value; var lastName = claimsPrincipal.FindFirst(ClaimTypes.Surname)?.Value; var input = new CompleteSamlLoginInput { RelayState = relayState, Email = email, FirstName = firstName, LastName = lastName }; var loginOutput = completeSamlLogin.Execute(input).Result; var cookieContent = authenticationCookieContentMapper.Map(loginOutput); httpContext.CreateAuthenticationCookieAsync(cookieContent, true).GetAwaiter().GetResult(); httpContext.Response.Headers.Add(SCloudHeaderNames.AntiCsrfToken, cookieContent.AntiCsrfToken.ToString()); // 手动处理重定向 if (!string.IsNullOrEmpty(relayState)) { httpContext.Response.Redirect(relayState); } else { httpContext.Response.Redirect("/"); // 默认重定向地址 } // 设置Handled为true,阻止库执行后续默认逻辑 command.Handled = true; };
关键说明
- 移除
SignInScheme是最直接的方式,因为该配置的核心作用就是让库自动将用户登录到指定Scheme并生成Cookie,而你需要完全自定义Cookie,所以不需要这个自动行为。 - 如果必须保留
SignInScheme(比如用于其他中间件交互),则使用AcsCommandCreated事件,在库执行登录操作前就拦截,自行处理所有流程,并设置command.Handled = true阻止默认逻辑。
内容的提问来源于stack exchange,提问作者user2412672
相关产品推荐
相关产品推荐

