【问题标题】:CORS error in authenticating .NET Core 2.2 API with Azure Active Directory使用 Azure Active Directory 对 .NET Core 2.2 API 进行身份验证时出现 CORS 错误
【发布时间】:2020-04-02 10:26:30
【问题描述】:

我正在尝试在基于 Visual Studio 2019 的基本 .NET Core 2.2 + React-project 模板构建的网页上使用 AzureAD 设置多租户 OpenId 身份验证。Core 2.2,因为 3.0 上的身份验证中间件未触发无论如何,这似乎是一个常见问题,Core 3.x 身份验证的文档很少,有时甚至是矛盾的。我想我什么都试过了,现在我很茫然。

这里的身份验证中间件似乎在调用 API 时根据服务器输出正确启动:

From javascript:
    // Tried also without custom headers and trying to make the middleware handle the thing by itself
    fetch('api/SampleData/WeatherForecasts', {
      method: "get",
      headers: new Headers({
        "Access-Control-Allow-Origin": "*",
        "Access-Control-Allow-Headers": "true"
      })
    })

Server output:
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
      Request starting HTTP/1.1 GET http://localhost:44363/api/SampleData/WeatherForecasts  
info: Microsoft.AspNetCore.Routing.EndpointMiddleware[0]
      Executing endpoint '********.Controllers.SampleDataController.WeatherForecasts (******)'
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[3]
      Route matched with {action = "WeatherForecasts", controller = "SampleData", area = "", page = ""}. Executing controller action with signature System.Collections.Generic.IEnumerable`1[******.Controllers.SampleDataController+WeatherForecast] WeatherForecasts() on controller ******.Controllers.SampleDataController (*********).
info: Microsoft.AspNetCore.Authorization.DefaultAuthorizationService[2]
      Authorization failed.
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[3]
      Authorization failed for the request at filter 'Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter'.
info: Microsoft.AspNetCore.Mvc.ChallengeResult[1]
      Executing ChallengeResult with authentication schemes ().
info: Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler[12]
      AuthenticationScheme: AzureADOpenID was challenged.
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2]
      Executed action *****.Controllers.SampleDataController.WeatherForecasts (*******) in 439.0343ms
info: Microsoft.AspNetCore.Routing.EndpointMiddleware[1]
      Executed endpoint '******.Controllers.SampleDataController.WeatherForecasts (*******)'
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
      Request finished in 464.9224ms 302 

但是当返回 HTTP 200 响应时,我总是在浏览器中得到 cors 错误:

Access to fetch at 'https://login.microsoftonline.com/common/oauth2/authorize?client_id=**********************&redirect_uri=https%3A%2F%2Flocalhost%3A44363%2Fsignin-oidc&response_type=id_token&scope=openid%20profile&response_mode=form_post&nonce=**************************************************&x-client-SKU=ID_NETSTANDARD2_0&x-client-ver=5.3.0.0' (redirected from 'https://localhost:44363/api/SampleData/WeatherForecasts') from origin 'https://localhost:44363' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

我可以手动打开登录页面,但浏览器因此无法重定向。我什至将应用程序发布为 Azure Web App,但仍然出现相同的 CORS 错误。我想我已经在 Startup.cs 中正确设置了所有内容,但似乎没有任何效果。然后我什至从 Azure Web App 设置了 cors-policy 以允许 * 来源,然后允许相关来源,但问题仍然存在。

Startup.cs:

    public void ConfigureServices(IServiceCollection services)
    {
      services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

      services.AddSpaStaticFiles(configuration => {
        configuration.RootPath = "ClientApp/build";
      });

      services.Configure<CookiePolicyOptions>(options => {
        options.CheckConsentNeeded = context => true;
        options.MinimumSameSitePolicy = SameSiteMode.None;
      });

      services.AddAuthentication(AzureADDefaults.AuthenticationScheme)
          .AddAzureAD(options => Configuration.Bind("AzureAd", options)).AddCookie();

      services.Configure<OpenIdConnectOptions>(AzureADDefaults.OpenIdScheme, options => {
        options.TokenValidationParameters = new TokenValidationParameters {
          ValidateIssuer = false,
        };

        options.Events = new OpenIdConnectEvents {
          OnTicketReceived = context => {
            return Task.CompletedTask;
          },
          OnAuthenticationFailed = context => {
            context.Response.Redirect("/Error");
            context.HandleResponse(); // Suppress the exception
            return Task.CompletedTask;
          }
        };
      });
      /*
      Tried also with this
      services.AddCors(setup => {
        setup.AddPolicy("corspolicy", policy => {
          policy
          .AllowAnyOrigin()
          .AllowAnyHeader()
          .AllowAnyMethod();          
        });
      });
      */
    }

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
      if (env.IsDevelopment()) {
        app.UseDeveloperExceptionPage();
      } else {
        app.UseExceptionHandler("/Error");
        // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
        app.UseHsts();
      }

      app.UseAuthentication(); // Tried putting this and .UseCors to different places
      app.UseStaticFiles();
      app.UseSpaStaticFiles();
      //app.UseCors("corspolicy"); 
      app.UseCors(policy => {
        policy
        .AllowAnyOrigin() // Tried with hardcoded origins
        .AllowAnyMethod()
        .AllowCredentials() // Tried without this also
        .AllowAnyHeader();        
      });
      app.UseHttpsRedirection();

      app.UseMvc(routes => {
        routes.MapRoute(
            name: "default",
            template: "{controller}/{action=Index}/{id?}");
      });
      app.UseSpa(spa => {
        spa.Options.SourcePath = "ClientApp";

        if (env.IsDevelopment()) {
          spa.UseReactDevelopmentServer(npmScript: "start");
        }
      });
    }

控制器:

  [Authorize]
  [EnableCors] // Tried with named policy and without EnableCors
  [ApiController] // Tried without this
  [Route("api/[controller]")]
  public class SampleDataController : Controller
  {
    private static string[] Summaries = new[]
    {
            "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
        };

    [HttpGet("[action]")]
    public IEnumerable<WeatherForecast> WeatherForecasts()
    {
      var rng = new Random();
      return Enumerable.Range(1, 5).Select(index => new WeatherForecast {
        DateFormatted = DateTime.Now.AddDays(index).ToString("d"),
        TemperatureC = rng.Next(-20, 55),
        Summary = Summaries[rng.Next(Summaries.Length)]
      });
    }
   // Nonrelevant things omitted
  }

【问题讨论】:

  • 您在.UseAuthentication() 之前尝试过.UserCors() 吗?
  • 您已配置 OpenID Connect 身份验证,该身份验证适用于交互式 Web 客户端。因为是API所以需要配置JWT Bearer认证,然后在前端使用MSAL.js处理用户的认证。
  • @Hadi 是的,就像我在代码 cmets 中所说的那样。
  • 这是因为浏览器接收重定向作为对其顶级请求的响应。您正在接收对 AJAX 请求的响应,这会导致 it 被重定向,从而导致 CORS 问题。

标签: c# authentication asp.net-core azure-active-directory openid


【解决方案1】:

经过长期调查,您的问题的简短答案是“您无法通过 ajax 请求实现它”。你实际上需要你的浏览器去那个你提出“挑战”请求的控制器。 这篇文章在这里解释了一切: https://www.blinkingcaret.com/2018/10/10/sign-in-with-an-external-login-provider-in-an-angular-application-served-by-asp-net-core/

【讨论】:

  • 虽然这可能会回答这个问题,但如果可能的话,您应该edit 回答您在回答本身中提供的链接中包含最重要的信息。如果链接停止工作或内容发生重大变化,这将有助于防止您的答案无效。
  • 谢谢你。你救了我好几个小时的恐惧。
  • Microsoft docs(选项 5 部分)还指出,如果特定于 login.microsoftonline.com 重定向,则无法解决此问题。
猜你喜欢
  • 2017-09-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-05-13
  • 2019-10-31
  • 1970-01-01
相关资源
最近更新 更多