如何在ASP.net Core WebAPI中启用CORS

kil*_*rin 148 c# rest cross-domain cors asp.net-core

我想做什么

我有一个Azure免费计划托管的后端ASP.Net核心Web API(源代码:https://github.com/killerrin/Portfolio-Backend).

我还有一个客户网站,我想要消费该API.客户端应用程序不会托管在Azure上,而是托管在Github Pages或我可以访问的其他Web托管服务上.因此,域名不会排队.

考虑到这一点,我需要在Web API端启用CORS,但是我现在已经尝试了好几个小时并拒绝工作.

我如何设置客户端 它只是一个用React.js编写的简单客户端.我在Jquery中通过AJAX调用API.React网站有效,所以我知道不是这样.Jquery API调用正如我在Attempt 1中确认的那样工作.这是我如何进行调用

    var apiUrl = "http://andrewgodfroyportfolioapi.azurewebsites.net/api/Authentication";
    //alert(username + "|" + password + "|" + apiUrl);
    $.ajax({
        url: apiUrl,
        type: "POST",
        data: {
            username: username,
            password: password
        },
        contentType: "application/json; charset=utf-8",
        dataType: "json",
        success: function (response) {
            var authenticatedUser = JSON.parse(response);
            //alert("Data Loaded: " + authenticatedUser);
            if (onComplete != null) {
                onComplete(authenticatedUser);
            }
        },
        error: function (xhr, status, error) {
            //alert(xhr.responseText);
            if (onComplete != null) {
                onComplete(xhr.responseText);
            }
        }
    });
Run Code Online (Sandbox Code Playgroud)

我试过了什么


尝试1 - "正确"的方式

https://docs.microsoft.com/en-us/aspnet/core/security/cors

我已经在微软网站上关注了这个教程,尝试了在Startup.cs中全局启用它的所有3个选项,在每个控制器上设置它并在每个Action上尝试它.

遵循此方法,Cross Domain可以工作,但只能在单个控制器上的一个Action上运行(POST到AccountController).对于其他一切,Microsoft.AspNetCore.Cors中间件拒绝设置标头.

Microsoft.AspNetCore.Cors通过NUGET 安装,版本是1.1.2

以下是我在Startup.cs中设置它的方法

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        // Add Cors
        services.AddCors(o => o.AddPolicy("MyPolicy", builder =>
        {
            builder.AllowAnyOrigin()
                   .AllowAnyMethod()
                   .AllowAnyHeader();
        }));

        // Add framework services.
        services.AddMvc();
        services.Configure<MvcOptions>(options =>
        {
            options.Filters.Add(new CorsAuthorizationFilterFactory("MyPolicy"));
        });

        ...
        ...
        ...
    }

    // This method gets called by the runtime. Use this method to configure 
    //the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IHostingEnvironment env,
    ILoggerFactory loggerFactory)
    {
        loggerFactory.AddConsole(Configuration.GetSection("Logging"));
        loggerFactory.AddDebug();

        // Enable Cors
        app.UseCors("MyPolicy");

        //app.UseMvcWithDefaultRoute();
        app.UseMvc();

        ...
        ...
        ...
    }
Run Code Online (Sandbox Code Playgroud)

正如你所看到的,我正在做所有事情.我在MVC之前添加了Cors两次,当这不起作用时,我试图[EnableCors("MyPolicy")]像每个控制器一样

[Route("api/[controller]")]
[EnableCors("MyPolicy")]
public class AdminController : Controller
Run Code Online (Sandbox Code Playgroud)

尝试2 - 暴力强迫它

https://andrewlock.net/adding-default-security-headers-in-asp-net-core/

在尝试上一次尝试几个小时之后,我想我会尝试通过手动设置标头来强制它,强制它们在每个响应上运行.我在本教程后就如何手动为每个响应添加标头做了这个.

这些是我添加的标题

.AddCustomHeader("Access-Control-Allow-Origin", "*")
.AddCustomHeader("Access-Control-Allow-Methods", "*")
.AddCustomHeader("Access-Control-Allow-Headers", "*")
.AddCustomHeader("Access-Control-Max-Age", "86400")
Run Code Online (Sandbox Code Playgroud)

这些是我试过的其他标题失败了

.AddCustomHeader("Access-Control-Allow-Methods", "GET, POST, PUT, PATCH, DELETE")
.AddCustomHeader("Access-Control-Allow-Headers", "content-type, accept, X-PINGOTHER")
.AddCustomHeader("Access-Control-Allow-Headers", "X-PINGOTHER, Host, User-Agent, Accept, Accept: application/json, application/json, Accept-Language, Accept-Encoding, Access-Control-Request-Method, Access-Control-Request-Headers, Origin, Connection, Content-Type, Content-Type: application/json, Authorization, Connection, Origin, Referer")
Run Code Online (Sandbox Code Playgroud)

使用此方法,正确应用了跨站点标头,它们显示在我的开发人员控制台和邮递员中.然而问题是,当它通过Access-Control-Allow-Origin检查时,webbrowser抛出了一个(我相信)Access-Control-Allow-Headers陈述的嘶嘶声415 (Unsupported Media Type)

所以蛮力方法也不起作用


最后

有没有人得到这个工作,可以伸出援助之手,或者只是能指出我正确的方向?


编辑

因此,为了让API调用完成,我不得不停止使用JQuery并切换到纯Javascript XMLHttpRequest格式.

尝试1

我设法Microsoft.AspNetCore.Cors通过遵循MindingData的答案来完成工作,除了在之前的Configure方法中.app.UseCorsapp.UseMvc

此外,当与Javascript API解决方案混合使用时options.AllowAnyOrigin(),通配符支持也开始起作用.

尝试2

所以我设法让Attempt 2(暴力强迫它)工作......唯一的例外是Wildcard for Access-Control-Allow-Origin不起作用,因此我必须手动设置有权访问它的域.

它显然不理想,因为我只是想让这个WebAPI向所有人开放,但它至少对我来说在一个单独的网站上工作,这意味着它是一个开始

app.UseSecurityHeadersMiddleware(new SecurityHeadersBuilder()
    .AddDefaultSecurePolicy()
    .AddCustomHeader("Access-Control-Allow-Origin", "http://localhost:3000")
    .AddCustomHeader("Access-Control-Allow-Methods", "OPTIONS, GET, POST, PUT, PATCH, DELETE")
    .AddCustomHeader("Access-Control-Allow-Headers", "X-PINGOTHER, Content-Type, Authorization"));
Run Code Online (Sandbox Code Playgroud)

Min*_*ata 193

因为您有一个非常简单的CORS策略(允许来自XXX域的所有请求),所以您不需要使它变得如此复杂.首先尝试执行以下操作(CORS的一个非常基本的实现).

如果您还没有,请安装CORS nuget包.

Install-Package Microsoft.AspNetCore.Cors
Run Code Online (Sandbox Code Playgroud)

在startup.cs的ConfigureServices方法中,添加CORS服务.

public void ConfigureServices(IServiceCollection services)
{
    services.AddCors(); // Make sure you call this previous to AddMvc
    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}
Run Code Online (Sandbox Code Playgroud)

然后在startup.cs的Configure方法中添加以下内容:

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    // Make sure you call this before calling app.UseMvc()
    app.UseCors(
        options => options.WithOrigins("http://example.com").AllowAnyMethod()
    );

    app.UseMvc();
}
Run Code Online (Sandbox Code Playgroud)

现在开始吧.策略适用于您需要针对不同操作的不同策略(例如,不同的主机或不同的标头).对于您的简单示例,您真的不需要它.从这个简单的例子开始,然后根据需要进行调整.

进一步阅读:http://dotnetcoretutorials.com/2017/01/03/enabling-cors-asp-net-core/

  • 在app.UseMvc之前使用app.UseCors,在Configure方法中似乎有效.出于某种原因,序列确实很重要. (21认同)
  • XMLHttpRequest 无法加载 http://andrewgodfroyportfolioapi.azurewebsites.net/api/Authentication。对预检请求的响应未通过访问控制检查:请求的资源上不存在“Access-Control-Allow-Origin”标头。因此,不允许访问 Origin 'http://localhost:3000'。响应的 HTTP 状态代码为 415。 (7认同)
  • 当你注册`app.UseCors`**AFTER**``app.UseMvc()`时,这不太可行.中间件按其注册顺序执行 (6认同)
  • 对我来说,2.0 中 CORS 的最大问题是它没有告诉我们出了什么问题,只是默默地未能设置 CORS 标头。_注意_:记住将所有必需的标头添加到策略中,否则它将失败(我有内容类型)。对我来说还有一件奇怪的事情,CORS 中间件不会制动请求处理,只是在日志中通知不允许来源,并且..进一步传递请求(中间件顺序是正确的)。 (2认同)
  • 我必须启用`options.DisableHttpsRequirement();`才能使其正常工作。似乎与https cors设置不适用。 (2认同)
  • .SetIsOriginAllowed((host) =&gt; true) 为我解决了这个问题。在配置中,app.UseCores() 为我解决了这个问题,其他都不起作用。 (2认同)
  • @MindingData 为什么我需要在纯 WebAPI 项目中添加 UseMVC() ?是否有必要加载所有 MVC 内容才能使 CORS 正常工作? (2认同)

小智 175

  • ConfigureServices中添加 services.AddCors(); BEFORE services.AddMvc();
  • Configure中添加UseCors

    app.UseCors(builder => builder
        .AllowAnyOrigin()
        .AllowAnyMethod()
        .AllowAnyHeader()
        .AllowCredentials());   
    app.UseMvc();
    
    Run Code Online (Sandbox Code Playgroud)

重点是app.UseCors之前添加app.UseMvc().

确保在MVC之前声明CORS功能,以便在MVC管道获得控制权并终止请求之前触发中间件.

  • 这真的应该得到更多的赞成作为一个良好的"起点".根据我25年的编码经验,我们总是很高兴知道如何打开闸门,以确保它确实"工作",然后根据需要关闭/保护. (16认同)
  • 仅举这一点,与`Configure()`相反,在`ConfigureServices()`中,顺序并不重要 (3认同)
  • 仅供参考 - CORS 规范还指出,如果存在 Access-Control-Allow-Credentials 标头,则将来源设置为“*”(所有来源)是无效的。这意味着您不能像上面那样将 `AllowCredentials()` 与 `AllowAnyOrigin()` 一起使用。要使用 `AllowCredentials()`,您需要设置 `WithOrigins()`。https://docs.microsoft.com/en-us/aspnet/core/security/cors?view=aspnetcore-2.2 (2认同)

Mo *_*sis 27

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {      
       app.UseCors(builder => builder
                .AllowAnyHeader()
                .AllowAnyMethod()
                .SetIsOriginAllowed((host) => true)
                .AllowCredentials()
            );
    }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddCors();
    }
Run Code Online (Sandbox Code Playgroud)

  • .SetIsOriginAllowed((host) =&gt; true) 为我解决了这个问题。 (2认同)

小智 23

我创建了自己的中间件类,对我有用,我认为.net核心中间件类有问题

public class CorsMiddleware
{
    private readonly RequestDelegate _next;

    public CorsMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public Task Invoke(HttpContext httpContext)
    {
        httpContext.Response.Headers.Add("Access-Control-Allow-Origin", "*");
        httpContext.Response.Headers.Add("Access-Control-Allow-Credentials", "true");
        httpContext.Response.Headers.Add("Access-Control-Allow-Headers", "Content-Type, X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Date, X-Api-Version, X-File-Name");
        httpContext.Response.Headers.Add("Access-Control-Allow-Methods", "POST,GET,PUT,PATCH,DELETE,OPTIONS");
        return _next(httpContext);
    }
}

// Extension method used to add the middleware to the HTTP request pipeline.
public static class CorsMiddlewareExtensions
{
    public static IApplicationBuilder UseCorsMiddleware(this IApplicationBuilder builder)
    {
        return builder.UseMiddleware<CorsMiddleware>();
    }
}
Run Code Online (Sandbox Code Playgroud)

并在startup.cs中以这种方式使用它

app.UseCorsMiddleware();
Run Code Online (Sandbox Code Playgroud)

  • 我也对此持怀疑态度,但它对我有用。我基本上尝试了所有其他方法来实现这一点,我可以在互联网上找到,但无论如何服务器都不会响应访问标头。这很好用。我正在运行 aspnetcore 2.1。 (2认同)
  • 也许“.net core 中间件类出了问题”,因为你在使用curl 或类似的东西测试它时没有添加标头“Origin”。当您在 js 代码中发出请求时,浏览器会自动添加此标头。 (2认同)

Fog*_*Day 20

我为此苦苦挣扎了几天。

我终于通过移动它得到工作app.UseCors(CORS_POLICY);TOPConfigure()

https://weblog.west-wind.com/posts/2016/sep/26/aspnet-core-and-cors-gotchas

确保在 > MVC 之前声明 CORS 功能,因为必须在 MVC 完成请求之前应用标头。

<= 即使我的应用程序没有调用UseMVC(),移到UseCors()顶部也解决了问题

还:

  • Microsoft.AspNetCore.Cors曾经是 .Net Core 2 及更低版本中必需的 NuGet 包;它现在自动成为 .Net Core 3 及更高版本中 Microsoft.AspNetCore 的一部分。
  • builder.AllowAnyOrigin().AllowCredentials()CORS 选项现在在 .Net Core 3 及更高版本中互斥
  • CORS 策略似乎要求 Angular 使用https. 无论 .Net Core 服务器的 CORS 配置如何,http URL 似乎都会给出 CORS 错误。例如,http://localhost:52774/api/Contacts会给出 CORS 错误;只需更改 URL 即可https://localhost:44333/api/Contacts工作。

附加说明

就我而言,CORS 在我移动app.UseCors()app.UseEndpoints(endpoints => endpoints.MapControllers()).

  • 如果您使用 Net Core 3,这应该就是答案。感谢您救了我的命! (5认同)
  • “使用端点路由时,必须将 CORS 中间件配置为在对 UseRouting 和 UseEndpoints 的调用之间执行。不正确的配置将导致中间件停止正常运行。” 这里https://docs.microsoft.com/en-us/aspnet/core/security/cors?view=aspnetcore-3.1#cpo (2认同)
  • 给我最好的答案谢谢。:) (2认同)

Leo*_*doX 16

对于.Net 6

var builder = WebApplication.CreateBuilder(args);
var apiCorsPolicy = "ApiCorsPolicy";

builder.Services.AddCors(options =>
{
    options.AddPolicy(name: apiCorsPolicy,
                      builder =>
                      {
                          builder.WithOrigins("http://localhost:4200", "https://localhost:4200")
                            .AllowAnyHeader()
                            .AllowAnyMethod()
                            .AllowCredentials();
                            //.WithMethods("OPTIONS", "GET");
                      });
});

builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();

var app = builder.Build();
app.UseHttpsRedirection();

app.UseCors(apiCorsPolicy);

app.UseAuthorization();
app.MapControllers();
app.Run();
Run Code Online (Sandbox Code Playgroud)

这里有更多例子


Tow*_*hid 14

在我的情况下,get根据MindingData的答案,只有请求才能正常工作.对于其他类型的请求,您需要编写:

app.UseCors(corsPolicyBuilder =>
   corsPolicyBuilder.WithOrigins("http://localhost:3000")
  .AllowAnyMethod()
  .AllowAnyHeader()
);
Run Code Online (Sandbox Code Playgroud)

别忘了添加 .AllowAnyHeader()


小智 12

对于 .NET 核心 3.1

就我而言,我在添加cors 中间件之前使用了https 重定向,并且能够通过更改它们的顺序来解决问题

我的意思是:

改变这个:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {

      ...
        
        app.UseHttpsRedirection();  

        app.UseCors(x => x
            .AllowAnyOrigin()
            .AllowAnyMethod()
            .AllowAnyHeader());

      ...

     }
Run Code Online (Sandbox Code Playgroud)

对此:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {

      ...
        
        app.UseCors(x => x
            .AllowAnyOrigin()
            .AllowAnyMethod()
            .AllowAnyHeader());

        app.UseHttpsRedirection(); 

      ...

     }
Run Code Online (Sandbox Code Playgroud)

顺便说一句,允许来自任何来源和方法的请求在生产阶段可能不是一个好主意,您应该在生产阶段编写自己的 cors 策略。


小智 8

为了扩展user8266077答案,我发现在我的用例中,我仍然需要为.NET Core 2.1预览中的预检请求提供OPTIONS响应:

// https://stackoverflow.com/a/45844400
public class CorsMiddleware
{
  private readonly RequestDelegate _next;

  public CorsMiddleware(RequestDelegate next)
  {
    _next = next;
  }

  public async Task Invoke(HttpContext context)
  {
    context.Response.Headers.Add("Access-Control-Allow-Origin", "*");
    context.Response.Headers.Add("Access-Control-Allow-Credentials", "true");
    // Added "Accept-Encoding" to this list
    context.Response.Headers.Add("Access-Control-Allow-Headers", "Content-Type, X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Accept-Encoding, Content-Length, Content-MD5, Date, X-Api-Version, X-File-Name");
    context.Response.Headers.Add("Access-Control-Allow-Methods", "POST,GET,PUT,PATCH,DELETE,OPTIONS");
    // New Code Starts here
    if (context.Request.Method == "OPTIONS")
    {
      context.Response.StatusCode = (int)HttpStatusCode.OK;
      await context.Response.WriteAsync(string.Empty);
    }
    // New Code Ends here

    await _next(context);
  }
}
Run Code Online (Sandbox Code Playgroud)

然后在Startup.cs中启用类似的中间件

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
  app.UseMiddleware(typeof(CorsMiddleware));
  // ... other middleware inclusion such as ErrorHandling, Caching, etc
  app.UseMvc();
}
Run Code Online (Sandbox Code Playgroud)

  • 我建议以这种方式添加中间件:`app.Use&lt;CorsMiddleware&gt;();` (2认同)

Sai*_*ath 6

以上过程均无济于事,然后我阅读解决了此问题的文章

下面是代码。

public void ConfigureServices(IServiceCollection services)
{
    // Add service and create Policy with options
    services.AddCors(options =>
    {
        options.AddPolicy("CorsPolicy",
            builder => builder.AllowAnyOrigin()
            .AllowAnyMethod()
            .AllowAnyHeader()
            .AllowCredentials() );
    });


    services.AddMvc(); 
}
Run Code Online (Sandbox Code Playgroud)

public void Configure(IApplicationBuilder app)
{
    // ...

    // global policy - assign here or on each controller
    app.UseCors("CorsPolicy");
Run Code Online (Sandbox Code Playgroud)

在我的行动方法之上

[EnableCors("CorsPolicy")]
Run Code Online (Sandbox Code Playgroud)

  • 这可能是一个坏主意:您不应该在同一应用程序中将中间件(`app.UseCors()`)与`[EnableCors()]`混合使用。您应该使用其中之一 - 但不能同时使用两者:https://docs.microsoft.com/en-us/aspnet/core/security/cors?view=aspnetcore-3.1:`使用 [EnableCors] 属性或中间件,不在同一个应用程序中。 (2认同)

ami*_*mad 6

最简单的解决方案是添加

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseHsts();
        }

        app.UseCors(options => options.AllowAnyOrigin());

        app.UseHttpsRedirection();
        app.UseMvc();
    }
Run Code Online (Sandbox Code Playgroud)

到 Startup.cs。


H.A*_*ani 6

对于 ASP.NET Core 3.1,这解决了我的问题 https://jasonwatmore.com/post/2020/05/20/aspnet-core-api-allow-cors-requests-from-any-origin-and-with-credentials

public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddCors();
            services.AddControllers();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            app.UseRouting();

            // global cors policy
            app.UseCors(x => x
                .AllowAnyMethod()
                .AllowAnyHeader()
                .SetIsOriginAllowed(origin => true) // allow any origin
                .AllowCredentials()); // allow credentials

            app.UseAuthentication();
            app.UseAuthorization();

            app.UseEndpoints(x => x.MapControllers());
        }
    }
Run Code Online (Sandbox Code Playgroud)


小智 5

对我来说,解决方案是纠正顺序:

app.UseCors();
app.UseAuthentication();
app.UseAuthorization();
Run Code Online (Sandbox Code Playgroud)


小智 5

以下是使用顶级语句配置 CORS 的 Program.cs 文件的 .NET 6 示例。可以看出,builder.Services.AddCors 和 app.UseCors 是必需的语句。两个带有注释的 UseCors 语句也有效,并且包含在内以显示其他选项。我没有对 ASP.NET API 控制器进行任何更改。

作为参考,我的开发 Angular 应用程序在 localhost:4200 上运行,并使用 https://localhost:7262 连接到开发 ASP.NET API 服务器。

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();

builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddCors();
var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();

app.UseAuthorization();

//app.UseCors(options => options.WithOrigins("http://localhost:4200").AllowAnyMethod());
//app.UseCors(options => options.WithOrigins("http://localhost:4200").WithMethods(new string[] {"POST", "PUT"}));
app.UseCors(options => options.AllowAnyOrigin().AllowAnyMethod());

app.MapControllers();

app.Run();
Run Code Online (Sandbox Code Playgroud)