我在努力做什么

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

当前回答

在我的情况下,我在UserRouting之前修复了UseCors ..

其他回答

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

下面是代码。

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

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

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

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

最简单的方法是

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

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

        app.UseHttpsRedirection();
        app.UseMvc();
    }

Startup.cs。

对我来说,它开始工作时,我已经明确设置的头,我正在发送。我添加了content-type header,然后它就工作了。

.net

.WithHeaders("Authorization","Content-Type")

javascript:

this.fetchoptions = {
        method: 'GET', 
        cache: 'no-cache', 
        credentials: 'include', 
        headers: {
            'Content-Type': 'application/json',
        },
        redirect: 'follow', 
    };