You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular调用.NET Core SAML接口对接Azure AD的CORS及认证异常问题

问题描述

初始CORS问题

我们正尝试为接收Angular应用请求的.NET Core API实现SAML认证,使用.NET 6环境下的Sustainsys.Saml2.AspNetCore2(2.9.2版本)包。通过浏览器直接访问API时,认证与授权功能正常。

但当Angular应用(运行于localhost:4200)连接后端.NET Core API(localhost:7085)并执行认证时,出现CORS错误:请求资源(Azure AD)缺少Access-Control-Allow-Origin头。我们发现调用身份提供商时,OPTIONS请求头中的Origin字段被设为null,身份提供商为Azure AD(托管于https://login.microsoftonline.com)。

我们认为这是由于前端与后端跨域,后端返回挑战重定向至Azure AD时,浏览器的同源策略导致Origin设为null,进而引发CORS问题。由于浏览器的同源策略限制,无法让Angular等前端JS应用直接允许跨域请求,除非服务器(此处为微软服务器)添加Access-Control-Allow-Origin头。

.NET SAML配置代码

public static AuthenticationBuilder AddSaml2Authentication(this IServiceCollection services, IConfiguration configuration)
{
    var saml2Configuration = new Saml2Configurations();
    configuration.Bind(ConfigurationKey, saml2Configuration);
    return services.AddAuthentication(options =>
    {
        options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;

        options.DefaultChallengeScheme = Saml2Defaults.Scheme;
    })
    .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, (options) =>
    {
        options.LoginPath = GetLoginPath(configuration);
        options.ReturnUrlParameter = "redirectUrl";
    })
    .AddSaml2(options =>
    {
        options.SPOptions.EntityId = new EntityId(saml2Configuration.SPEntityId);
        options.IdentityProviders.Add(new IdentityProvider(
        new EntityId(saml2Configuration.IdPEntityId),
        options.SPOptions)
        {
            MetadataLocation = saml2Configuration.IdPMetadataLocation
        });
    });
}

认证控制器代码

public class AccountController : Controller
{
    [AllowAnonymous]
    [HttpGet("Login")]
    public IActionResult Login(string redirectUrl)
    {
        string? redirectUri = Url.Action(nameof(LoginCallback), new { redirectUrl });
        var properties = new AuthenticationProperties()
        {
            RedirectUri = redirectUri
        };
        ChallengeResult result = Challenge(properties, Saml2Defaults.Scheme);
        return result;
    }

    [AllowAnonymous]
    [HttpGet("Callback")]
    public async Task<IActionResult> LoginCallback(string redirectUrl)
    {
        AuthenticateResult authenticateResult = await HttpContext.AuthenticateAsync(CookieAuthenticationDefaults.AuthenticationScheme);
        if (!authenticateResult.Succeeded)
        {
            return Unauthorized();
        }
        IEnumerable<Claim>? claimCollection = authenticateResult.Principal?.Claims;
        if (claimCollection == null || !claimCollection.Any())
        {
            return Problem(statusCode: StatusCodes.Status400BadRequest);
        }
        if (!string.IsNullOrEmpty(redirectUrl))
        {
            return Redirect(redirectUrl);
        }
        return Ok();
    }
}

更新后的InResponseTo错误

我们尝试将SAML登录URL返回给前端并由其发起GET请求,成功在Azure门户完成登录,但点击“SignIn”按钮后出现新错误:

处理请求时发生未处理的异常。
UnexpectedInResponseToException: 收到的消息_5d94ac02-98e3-4219-800e-8f389c747b3c包含意外的InResponseTo值"idcd3e9548a6184c7aa0e2c3a061b107f9"。未找到保存请求状态的Cookie,因此该消息不应包含InResponseTo属性。此错误通常发生在SP发起登录时设置的Cookie丢失的情况下。

解决方案

解决初始CORS问题

SAML认证是基于浏览器重定向的流程,不适合通过前端AJAX请求直接触发。正确的做法是让前端引导用户跳转到后端的登录端点,而非AJAX调用:

  • 前端调整:当需要认证时,直接通过浏览器跳转至后端/Login接口(例如window.location.href = 'https://localhost:7085/Login?redirectUrl=https://localhost:4200/目标页面'),整个认证流程在浏览器中完成,不会触发CORS检查。
  • 后端CORS配置:确保后端已正确配置CORS允许前端域名的请求,但注意登录流程本身依赖重定向,无需AJAX跨域调用。

解决InResponseTo错误

该错误核心是SP发起登录时生成的状态Cookie丢失,导致回调时无法匹配响应的InResponseTo值,需从Cookie跨域配置和流程逻辑调整:

  1. 配置Cookie跨域属性
    在Cookie认证和Sustainsys.Saml2配置中,设置Cookie的SameSite为None,并开启Secure(生产环境):

    .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, (options) =>
    {
        options.LoginPath = GetLoginPath(configuration);
        options.ReturnUrlParameter = "redirectUrl";
        options.Cookie.SameSite = SameSiteMode.None;
        options.Cookie.SecurePolicy = CookieSecurePolicy.Always; // 开发环境可改为CookieSecurePolicy.None
        options.Cookie.HttpOnly = true;
    })
    .AddSaml2(options =>
    {
        // 原有配置...
        options.SPOptions.SystemCookieSameSite = SameSiteMode.None;
    })
    
  2. 调整前端跳转逻辑
    不要通过AJAX获取登录URL再跳转,直接让用户浏览器导航到后端登录端点,确保Cookie正确绑定到后端域名,回调时可正常读取。

  3. 验证回调流程
    确保回调URL属于后端域名,认证完成后再重定向回前端页面,保证整个流程的Cookie都在后端域名下,避免丢失。

总结

SAML认证是基于浏览器会话的重定向流程,不能用AJAX跨域调用触发。正确流程为:

  1. 前端检测到未认证时,引导用户跳转到后端/Login接口,并携带前端回调地址。
  2. 后端发起SAML挑战,重定向到Azure AD登录。
  3. Azure AD登录完成后,回调到后端/Callback接口,完成认证并设置Cookie。
  4. 后端重定向回前端指定页面,此时前端可通过AJAX调用后端API,浏览器会自动携带认证Cookie。

内容的提问来源于stack exchange,提问作者Hugo Mata

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 23:54:53