在 .NET Core Web API 上为 CORS 启用选项 header

Enable OPTIONS header for CORS on .NET Core Web API

我在 Whosebug 上找不到解决方案后解决了这个问题,所以我在这里分享我的问题和答案中的解决方案。

使用 AddCors 在我的 .NET Core Web Api 应用程序中启用跨域策略后,它仍然无法在浏览器中运行。这是因为包括 Chrome 和 Firefox 在内的浏览器将首先发送一个 OPTIONS 请求,而我的应用程序仅响应 204 No Content.

将中间件 class 添加到您的项目以处理 OPTIONS 动词。

using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Hosting;

namespace Web.Middlewares
{
    public class OptionsMiddleware
    {
        private readonly RequestDelegate _next;

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

        public Task Invoke(HttpContext context)
        {
            return BeginInvoke(context);
        }

        private Task BeginInvoke(HttpContext context)
        {
            if (context.Request.Method == "OPTIONS")
            {
                context.Response.Headers.Add("Access-Control-Allow-Origin", new[] { (string)context.Request.Headers["Origin"] });
                context.Response.Headers.Add("Access-Control-Allow-Headers", new[] { "Origin, X-Requested-With, Content-Type, Accept" });
                context.Response.Headers.Add("Access-Control-Allow-Methods", new[] { "GET, POST, PUT, DELETE, OPTIONS" });
                context.Response.Headers.Add("Access-Control-Allow-Credentials", new[] { "true" });
                context.Response.StatusCode = 200;
                return context.Response.WriteAsync("OK");
            }

            return _next.Invoke(context);
        }
    }

    public static class OptionsMiddlewareExtensions
    {
        public static IApplicationBuilder UseOptions(this IApplicationBuilder builder)
        {
            return builder.UseMiddleware<OptionsMiddleware>();
        }
    }
}

然后在 Configure 方法的 Startup.cs 中添加 app.UseOptions(); 作为第一行。

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    app.UseOptions();
}

我知道已经回答了。只是用更新的信息回答。所以它会帮助别人。

它现在内置于 ASP.NET 核心框架中。

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

并替换

    app.UseCors(builder =>
   builder.WithOrigins("http://example.com"));

        app.UseCors(builder =>
       builder.WithOrigins("http://example.com")
              .AllowAnyHeader()
              .AllowAnyMethod()
              .AllowCredentials());

这对我有用:

确保:

app.UseCors(builder => {
    builder.AllowAnyOrigin();
    builder.AllowAnyMethod();
    builder.AllowAnyHeader();
});

发生在任何这些之前:

app.UseHttpsRedirection();
app.UseDefaultFiles();
app.UseStaticFiles();
app.UseCookiePolicy();

记住,我们正在处理 "pipeline"。 cors 的东西必须放在第一位。

-金扎尼

我想在单个方法上允许这样做,而不是使用中间件在任何方法上允许这样做。这就是我最后做的事情:

'OPTIONS' 方法的手动处理

[HttpOptions("/find")]
public IActionResult FindOptions()
{
    Response.Headers.Add("Access-Control-Allow-Origin", new[] { (string)Request.Headers["Origin"] });
    Response.Headers.Add("Access-Control-Allow-Headers", new[] { "Origin, X-Requested-With, Content-Type, Accept" });
    Response.Headers.Add("Access-Control-Allow-Methods", new[] { "POST, OPTIONS" }); // new[] { "GET, POST, PUT, DELETE, OPTIONS" }
    Response.Headers.Add("Access-Control-Allow-Credentials", new[] { "true" });
    return NoContent();
}

[HttpPost("/find")]
public async Task<IActionResult> FindOptions([FromForm]Find_POSTModel model)
{
    AllowCrossOrigin();
    
    // your code...
}

private void AllowCrossOrigin()
{
    Uri origin = null;
    Uri.TryCreate(Request.Headers["Origin"].FirstOrDefault(), UriKind.Absolute, out origin);

    if (origin != null && IsOriginAllowed(origin))
        Response.Headers.Add("Access-Control-Allow-Origin", $"{origin.Scheme}://{origin.Host}");
}

当然,您可以根据需要实施IsOriginAllowed

private bool IsOriginAllowed(Uri origin)
{
    const string myDomain = "mydomain.com";
    const string[] allowedDomains = new []{ "example.com", "sub.example.com" };

    return 
           allowedDomains.Contains(origin.Host) 
           || origin.Host.EndsWith($".{myDomain}");
}

您可以在 how to enable CORS for POST requests on a single endpoint

上找到更多详细信息

不需要额外的中间件。正如上面已经提到的,唯一需要的是 Cors 配置中允许的 OPTIONS 方法。 您可以按照此处的建议使用 AllowAnyMethod:https://whosebug.com/a/55764660/11921910

但是只允许这样的特定内容更安全:

app.UseCors(builder => builder
.WithOrigins("https://localhost", "https://production.company.com") /* list of environments that will access this api */
.WithMethods("GET", "OPTIONS") /* assuming your endpoint only supports GET */
.WithHeaders("Origin", "Authorization") /* headers apart of safe-list ones that you use */
);

有些 headers 总是允许的: https://developer.mozilla.org/en-US/docs/Glossary/CORS-safelisted_request_header

我想针对我在本地测试 api 和客户端 Web 应用程序的具体情况给出具体答案。我知道这是一个迟到的条目,但 CORS 在 dot net 核心中发生了很大变化,我想,像我这样的新手可能会受益于完整的 post。

对我来说,这是两个背靠背发生的问题。

  1. CORS 拒绝错误
  2. 还有 Firefox 上的 OPTIONS 问题(我假设 chrome 会做同样的事情)
  3. 我的 API 也是 运行 HTTPS
  4. 网络应用没有 HTTPS
  5. 他们都运行在本地,为清楚起见再次提及这一点。

首先,这会转到 public void ConfigureServices(IServiceCollection services)

        //lets add some CORS stuff 
        services.AddCors(options =>
        {
            options.AddDefaultPolicy(builder => {
                builder.WithOrigins("http://localhost:3000",
                                    "http://www.contoso.com");
                builder.AllowAnyMethod();
                builder.AllowAnyHeader();
                builder.AllowCredentials();
            });
        });

然后,这个,转到,public void Configure(IApplicationBuilder app, IWebHostEnvironment env)

  app.UseCors();

欢迎。

[HttpOptions("/find")] public IActionResult FindOptions()

{
    Response.Headers.Add("Access-Control-Allow-Origin", new[] { (string)Request.Headers["Origin"] });
    Response.Headers.Add("Access-Control-Allow-Headers", new[] { "Origin, X-Requested-With, Content-Type, Accept" });
    Response.Headers.Add("Access-Control-Allow-Methods", new[] { "POST, OPTIONS" }); // new[] { "GET, POST, PUT, DELETE, OPTIONS" }
    Response.Headers.Add("Access-Control-Allow-Credentials", new[] { "true" });
    return NoContent();
}`enter code here`

AspNetCoreModuleV2 OPTIONS问题

.Net 核心模块不知道如何处理导致预检 CORS 问题的 OPTIONS,因此解决方案是排除 OPTIONS 动词由它处理。这是通过将 * 替换为您想要的动词(选项除外)来完成的。不用担心,OPTIONS 动词将由默认加载的 OPTIONSHandler 处理:

IIS

解决方法:修改web.config

 <add name="aspNetCore" path="*" verb="* modules="AspNetCoreModuleV2" resourceType="Unspecified" />

像这样:

<add name="aspNetCore" path="*" verb="GET,POST,PUT,DELETE" modules="AspNetCoreModuleV2" resourceType="Unspecified" />

IIS Express:对于 Visual Studio 调试器

我尝试修改 .vs\ProjectName\config\applicationhost.config 在文件的底部,但没有希望。因此,在这种特定情况下,您可以使用所选答案。

实际上,none 个答案对我有用,但我终于弄清楚了问题所在,我不敢相信 我刚搬家 app.UserCors("PolicyName"); app.UseAuthorization(); 之前 它开始工作了!

我认为这可能对某人有帮助。

services.AddCors(options =>
{
  options.AddPolicy("EnableCORS", bl =>
  {
    bl.WithOrigins(origins)
      .AllowAnyMethod()
      .AllowAnyHeader()
      .AllowCredentials()
      .Build();
  });
});


..........................
app.UseAuthentication();
app.UseCors("EnableCORS");
.....
app.UseAuthorization();