首页 > 解决方案 > 具有多个来源和多个标头的 .net 核心 cors

问题描述

我有不同的来源,需要通过 cors 策略允许不同的标头。

例如:

1/ - 来源:abc.com - 标题:A、B

2/ - 来源:bcd.com - 标题:A、C

这是我的代码:

services.AddCors(opt =>
            {
                opt.AddPolicy(
                    "ABC",
                    builder =>
                    {
                      builder.WithOrigins("abc.com")
                          .WithHeaders("A", "B");
                    });
        opt.AddPolicy(
                    "BCD",
                    builder =>
                    {
                      builder.WithOrigins("bcd.com")
                          .WithHeaders("A", "C");
                    });
        });

并在 Startup.Configure 中:

builder.UseCors("ABC");
builder.UseCors("BCD");

有关原点的一切工作正常,但问题在于标题。标头仅适用于第一个策略。在上面的代码中,标头可以与 Policy ABC 一起使用。我可以按预期发送带有标头 A 或标头 B 的请求,但对于策略 BCD,如果我发送没有标头的请求。它有效,但如果我发送带有标头 A 或 C 的请求,它就不起作用。

如果我将 BCD 移动到 ABC 之上,BCD 标题就可以了。

标签: asp.net-corecors

解决方案


您可以创建一个自定义中间件,该中间件根据请求的来源检查策略。

public class CustomCorsMiddleware
{
    private readonly RequestDelegate _next;
    private readonly ICorsService _corsService;
    private readonly ICorsPolicyProvider _corsPolicyProvider;
    private readonly IDictionary<string, string> _policies;

    public CustomCorsMiddleware(
        RequestDelegate next,
        ICorsService corsService,
        ICorsPolicyProvider policyProvider,
        IDictionary<string, string> policies)
    {
        _next = next ?? throw new ArgumentNullException(nameof(next));
        _corsService = corsService ?? throw new ArgumentNullException(nameof(corsService));
        _corsPolicyProvider = policyProvider ?? throw new ArgumentNullException(nameof(policyProvider));
        _policies = policies;
    }

    public async Task Invoke(HttpContext context)
    {
        if (context.Request.Headers.ContainsKey(CorsConstants.Origin))
        {
            string policyName;
            bool hasPolicy = this._policies.TryGetValue(context.Request.Headers[CorsConstants.Origin], out policyName);

            if (!String.IsNullOrEmpty(policyName) && hasPolicy)
            {
                CorsPolicy corsPolicy = await _corsPolicyProvider.GetPolicyAsync(context, policyName);
                if (corsPolicy != null)
                {
                    var corsResult = _corsService.EvaluatePolicy(context, corsPolicy);
                    _corsService.ApplyResult(corsResult, context.Response);

                    var accessControlRequestMethod = context.Request.Headers[CorsConstants.AccessControlRequestMethod];
                    if (string.Equals(
                            context.Request.Method,
                            CorsConstants.PreflightHttpMethod,
                            StringComparison.OrdinalIgnoreCase) &&
                            !StringValues.IsNullOrEmpty(accessControlRequestMethod))
                    {
                        // Since there is a policy which was identified,
                        // always respond to preflight requests.
                        context.Response.StatusCode = StatusCodes.Status204NoContent;
                        return;
                    }
                }
            }
        }

        await _next(context);
    }
}

在您的 Startup.cs 中,您必须定义策略并提供中间件的映射。

public void ConfigureServices(IServiceCollection services) 
{
  services.AddCors(opt => {
    opt.AddPolicy(
      "ABC",
      builder => {
        builder.WithOrigins("abc.com")
          .WithHeaders("A", "B");
      }
    );
    opt.AddPolicy(
      "BCD",
      builder => {
        builder.WithOrigins("bcd.com")
          .WithHeaders("A", "C");
      }
    );
  });
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    IDictionary<string, string> mappings = new Dictionary<string, string>();
    mappings["abc.com"] = "ABC";
    mappings["bcd.com"] = "BCD";
    app.UseMiddleware<CustomCorsMiddleware>(mappings);
}

希望这可以帮助!


推荐阅读