使用 Angular 应用程序调用 .NET Core API(使用 Sustainsys.Saml2 库和 Azure Active Directory 作为身份提供商)时出现 CORS 问题

问题描述 投票:0回答:1

当请求来自 Angular 应用程序时,我们尝试在 .NET Core API 中实现 SAML 身份验证。我们正在使用适用于 .NET 6 的包 Sustainsys.Saml2.AspNetCore2(版本 2.9.2)。我们已成功使该包正常工作,在通过浏览器直接访问 API 时验证并授权用户访问我们的 Web API .

现在我们正在尝试让 Angular 应用程序连接到后端 API,并仍然执行身份验证。但是,我们收到 CORS 错误:请求的资源(即 Azure AD)中缺少“Access-Control-Allow-Origin”标头。

我们注意到,调用身份提供者时,OPTIONS 请求标头中的“Origin”字段设置为

null
。身份提供程序托管在 https://login.microsoftonline.com (Azure AD)。

我们认为,由于前端在

localhost:4200
上运行,并且它在
localhost:7085
中调用后端 .NET api,并且后端返回一个将浏览器重定向到 https://login.microsoftonline.com 的质询,因此导致由于这种安全性,浏览器将“Origin”设置为 null 也会导致 CORS 问题。如果没有服务器(在本例中为 Microsoft 的服务器)包含 Access-Control-Allow-Origin 标头,让 Angular 或任何客户端 JavaScript 应用程序直接允许跨源请求是不可行的。这是由于浏览器强制执行的安全性(称为同源策略)。

作为参考,这是我们在 .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();
    }
}

如何解决此 CORS 问题并能够通过 Angular 应用程序和 .NET Core Api 使用 SAML 进行身份验证?

更新

我们尝试将 SAML 登录 URL 返回到前端并从那里发起 GET 请求。这使我们能够使用 Azure 门户中的凭据成功访问和登录。然而,点击“登录”按钮后出现了新的错误:

处理请求时发生未处理的异常。 UnexpectedInResponseToException:已收到消息 _5d94ac02-98e3-4219-800e-8f389c747b3c 包含意外的 InResponseTo“idcd3e9548a6184c7aa0e2c3a061b107f9”。没有 cookie 保存状态 已找到请求,因此该消息预计不会有 InResponseTo 属性。如果 cookie 设置,通常会发生此错误 当进行 SP 发起的登录时已丢失。

angular .net-core active-directory saml
1个回答
0
投票

更改要使用的 Angular 前端 尝试时使用

window.location.href
而不是 GET 请求 对用户进行身份验证解决了 CORS 问题。

基本上,当我们使用 GET 请求时,重定向会抛出 CORS 错误,因为后端尝试使用 AJAX 和 XMLHttpRequest 重定向来重定向前端,而浏览器出于安全考虑而阻止了此行为。我们可以通过更新身份提供程序(在本例中为 Microsoft Azure AD)以允许我们的服务器作为源来解决此 CORS 问题,但由于它是 Microsoft 服务器,因此我们无法这样做。因此,解决方案包括使用

window.location.href
将浏览器完全重定向到我们的后端端点。这可以避免 CORS 问题,因为重定向是由标准浏览器导航处理的。

角度代码:

// Replace the previous GET request with the following code:
window.location.href = `your-backend-endpoint/Login?redirect=${encodeURIComponent(window.location.href)/dashboard}`;

PS:解决这个问题后,我们在 Angular 前端添加了两条新路由:

  • /login
    :使用
    window.location.href
    将浏览器重定向到我们的后端
    /Login
    来处理身份验证。
  • /dashboard
    :首先向
    /Callback
    后端端点发出 GET 请求以验证用户是否已通过身份验证,然后使用经过身份验证的用户加载我们的仪表板。如果
    /Callback
    请求返回 401 Unauthorized,我们只需将用户重定向到“/login”路由来处理如上所示的身份验证。 PS.2:后端端点
    /Login
    /Callback
    已作为 GitHub 上 Sustainsys 库中的示例实现。我们不需要在后端进行任何更改来解决此问题,只需在前端进行即可。
© www.soinside.com 2019 - 2024. All rights reserved.