我在努力做什么

我有一个后台ASP。Net Core Web API托管在Azure免费计划上(源代码:https://github.com/killerrin/Portfolio-Backend)。

我也有一个客户端网站,我想让消费该API。客户端应用程序不会托管在Azure上,而是托管在Github Pages或我可以访问的其他Web托管服务上。正因为如此,域名不会排成一行。

研究这个问题,我需要在Web API端启用CORS,但是我已经尝试了几个小时,现在它拒绝工作。

我如何有客户端设置 它只是一个用React.js编写的简单客户端。我通过Jquery中的AJAX调用api。React网站工作,所以我知道它不是。Jquery API调用工作,我在尝试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);
            }
        }
    });

我所尝试过的


尝试1 -“正确”的方式

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

我已经遵循微软网站上的本教程,尝试在Startup.cs中全局启用它的所有3个选项,在每个控制器上设置它,并在每个动作上尝试它。

按照这种方法,跨域工作,但只能在单个控制器上的单个动作上工作(POST到AccountController)。对于其他任何事情,Microsoft.AspNetCore.Cors中间件拒绝设置头文件。

我通过NUGET安装了Microsoft.AspNetCore.Cors,版本为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();

        ...
        ...
        ...
    }

如你所见,我都是照做的。我两次都在MVC之前添加了Cors,当这不起作用时,我尝试在每个控制器上都添加[EnableCors(“MyPolicy”)]

[Route("api/[controller]")]
[EnableCors("MyPolicy")]
public class AdminController : Controller

尝试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")

这些是我尝试失败的其他头

.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")

有了这个方法,跨站点的头被正确地应用,他们显示在我的开发控制台和邮差。然而,问题是,当它通过访问控制-允许起源检查时,web浏览器抛出了一个嘘声(我相信)访问控制-允许头部声明415(不支持的媒体类型)

所以暴力法也不管用


最后

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


EDIT

因此,为了让API调用顺利进行,我不得不停止使用JQuery,转而使用纯Javascript的XMLHttpRequest格式。

尝试1

我设法让Microsoft.AspNetCore.Cors通过遵循MindingData的答案工作,除了在配置方法中将app.UseCors放在app.UseMvc之前。

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

尝试2

所以我已经设法让尝试2(暴力强迫它)工作…唯一的例外是,通配符访问控制-允许-起源不工作,因此我必须手动设置有权限访问它的域。

这显然不是理想的,因为我只是想让这个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"));

当前回答

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());
        }
    }

其他回答

我为此纠结了好几天。

我终于让它通过移动app.UseCors(CORS_POLICY);到Configure()的顶部。

https://weblog.west-wind.com/posts/2016/sep/26/aspnet-core-and-cors-gotchas 确保在> MVC之前声明CORS功能 头必须在MVC完成请求之前应用。 <=即使我的应用程序没有调用UseMVC(),移动UseCors()到顶部修复了这个问题

另外:

Microsoft.AspNetCore.Cors used to be a required NuGet package in .Net Core 2 and lower; it's now automatically a part of Microsoft.AspNetCore in .Net Core 3 and higher. builder.AllowAnyOrigin() and .AllowCredentials() CORS options are now mutually exclusive in .Net Core 3 and higher CORS policy seems to require Angular call the server with https. An http URL seemed to give a CORS error regardless of the .Net Core server's CORS configuration. For example, http://localhost:52774/api/Contacts would give a CORS error; simply changing the URL to https://localhost:44333/api/Contacts worked.

另外注意:

在我的情况下,CORS不会工作,直到我移动app.UseCors()以上app.UseEndpoints(endpoints => endpoints. mapcontrollers())。

以上的步骤都没有帮助,然后我读了一篇文章,解决了这个问题。

下面是代码。

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(); 
}

and

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

    // global policy - assign here or on each controller
    app.UseCors("CorsPolicy");

在actionmethod的顶部

[EnableCors("CorsPolicy")]

The

Microsoft.AspNetCore.Cors

将允许您使用内置功能进行CORS,但它不处理OPTIONS请求。 到目前为止,最好的解决方法是创建一个新的中间件,就像之前的文章中建议的那样。检查以下帖子中标记为正确的答案:

启用。net核心Web API中CORS的OPTIONS头

为了扩展user8266077的回答,我发现我仍然需要在。net Core 2.1-preview中为preflight请求提供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);
  }
}

然后在Startup.cs中启用中间件

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

下面是。net 6中使用顶级语句配置CORS的Program.cs文件示例。可以看到,builder.Services.AddCors和app.UseCors是必需的语句。两个带注释的UseCors语句也可以工作,并用于显示其他选项。我没有对ASP做任何更改。NET API控制器。

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

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();