我在努力做什么

我有一个后台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"));

当前回答

为了扩展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();
}

其他回答

在ASP中对我有效的解决方案。NET Core 3.1:

public void ConfigureServices(IServiceCollection services)
        {
            services.AddCors(options =>
            {
                options.AddPolicy("CorsPolicy",
                    builder => builder.AllowAnyOrigin()
                    .AllowAnyMethod()
                    .AllowAnyHeader());
            });
            services.AddControllersWithViews();
        }

然后修改如下:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            app.UseCors("CorsPolicy");

            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/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.UseHttpsRedirection();
            app.UseStaticFiles();

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

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllerRoute(
                    name: "default",
                    pattern: "{controller=Home}/{action=Index}/{id?}");
            });
        }

程序运行正常,错误得到解决。

在ConfigureServices中添加services.AddCors();之前services.AddMvc (); 在“配置”中添加UseCors app.UseCors(生成器=>生成器 .AllowAnyOrigin () .AllowAnyMethod () .AllowAnyHeader ()); app.UseMvc ();

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

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

在上面的方法起作用后,你可以改变它,配置一个特定的ORIGIN来接受api调用,避免让你的api对任何人开放

public void ConfigureServices(IServiceCollection services)
{
    services.AddCors(options => options.AddPolicy("ApiCorsPolicy", builder =>
    {
        builder.WithOrigins("http://localhost:4200").AllowAnyMethod().AllowAnyHeader();
    }));

    services.AddMvc();
}

在configure方法中告诉CORS使用刚刚创建的策略:

app.UseCors("ApiCorsPolicy");
app.UseMvc();

我刚找到了这篇关于这个主题的简明文章 https://dzone.com/articles/cors-in-net-core-net-core-security-part-vi

我使用的是。net CORE 3.1,当我意识到我的代码已经开始实际工作,但我的调试环境被打破时,我花了很长时间用这一个敲我的头,所以如果你试图排除问题,这里有2个提示:

如果您试图使用ASP记录响应头。NET中间件,“Access-Control-Allow-Origin”头即使在那里也不会显示。我不知道如何,但它似乎是在管道之外添加的(最后我不得不使用wireshark来查看它)。 . net CORE不会在响应中发送“Access-Control-Allow-Origin”,除非你的请求中有一个“Origin”头。邮差不会自动设置,所以你需要自己添加。

简单易行的方法。

安装包

安装包Microsoft.AspNetCore.Cors

把下面的代码放在startup.cs文件中

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

对于。net Core 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();

这里有更多的例子