简体   繁体   中英

CORS not working in ASP.NET Web API 2 app

You know, the usual: CORS isn't working. Chrome serves me up with this:

Fetch API cannot load https://url-to-my-api-thing . No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin ' https://url-to-the-origin-thing ' is therefore not allowed access. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

I have an ASP.NET Web API 2 application which uses the OWIN pipeline and is hosted in IIS.

Here's how I (try to) set up CORS in my Configuration method:

// ... container setup above, CORS is the first middleware ...

var corsPolicyProvider = new CorsPolicyProvider(_corsOrigins, container.GetInstance<ILogger>);
app.UseCors(new CorsOptions
{
    PolicyProvider = corsPolicyProvider
});

app.UseStageMarker(PipelineStage.Authenticate);

configuration.Services.Replace(typeof(IExceptionHandler), new PassThroughExceptionHandler());
configuration.MapHttpAttributeRoutes();
app.UseWebApi(configuration);

And here's what my CorsPolicyProvider class looks like:

public class CorsPolicyProvider : ICorsPolicyProvider
{
    private readonly Regex _corsOriginsRegex;
    private readonly string _defaultCorsOrigin;
    private readonly Func<ILogger> _scopedLoggerCreator;

    public CorsPolicyProvider(string corsOrigins, Func<ILogger> scopedLoggerCreator)
    {
        _corsOriginsRegex = new Regex($"({corsOrigins})", RegexOptions.IgnoreCase);
        _defaultCorsOrigin = corsOrigins?.Split('|').FirstOrDefault();
        _scopedLoggerCreator = scopedLoggerCreator;
    }

    public Task<CorsPolicy> GetCorsPolicyAsync(IOwinRequest request)
    {
        var logger = _scopedLoggerCreator();

        var allowedOrigin = _defaultCorsOrigin;
        string[] origins;
        request.Headers.TryGetValue("Origin", out origins);
        var origin = origins?.FirstOrDefault();
        if (origin != null && Uri.IsWellFormedUriString(origin, UriKind.Absolute) && _corsOriginsRegex.IsMatch(new Uri(origin).Host))
            allowedOrigin = origins.FirstOrDefault();

        var policy = new CorsPolicy
        {
            Origins = { allowedOrigin },
            Methods = { HttpMethod.Get.Method, HttpMethod.Post.Method, HttpMethod.Put.Method, HttpMethod.Delete.Method },
            Headers = { "accept", "content-type" },
            SupportsCredentials = true,
            PreflightMaxAge = 1728000
        };

        logger?.Verbose("Resolving CORS policy: {@CorsPolicy}", policy);

        return Task.FromResult(policy);
    }
}

Why is this policy never triggered, or at best malfunctioning? If I set a breakpoint and explicitly send an OPTIONS request when testing locally, it enters the GetCorsPolicyAsync method, and also logs the request as expected. But when the API is on the server and I try to call it from a website in Chrome, it never logs the request and it just tells me there's no CORS header.

... and like clockwork, the moment I post something on SO I find the answer. There was a CORS header, and the request was being logged, but the environment had the wrong configuration, so the origin (which was then invalid since it was a different environment) was correctly being blocked, and the logs end up on the wrong server. Fixed the configuration, and it works as expected again.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM