ASP.NET Core Disable CORS for specific controllers

Refresh

April 2019

Views

607 time

1

I have different set of controllers in my application (let's say A and B). CORS for A controller needs to be enabled and disabled for B controllers. I have configured CORS via the policies in the following way:

ConfigureServices method:

services.AddCors(
    options =>
    {
        options.AddPolicy(
            "AllowCors",
            builder =>
                {
                    builder.AllowAnyOrigin().WithMethods(
                        HttpMethod.Get.Method,
                        HttpMethod.Put.Method,
                        HttpMethod.Post.Method,
                        HttpMethod.Delete.Method).AllowAnyHeader().WithExposedHeaders("CustomHeader");
                });
    });
services.AddMvcCore()

Configure method

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

Set of A controllers has EnableCors attribute

[EnableCors("AllowCors")]
public class ControllerA1: Controller

CORS works for set of A controller as expected (tested via the browser). However, it also does work for B controllers! I even tried to disable CORS with DisableCors attribute explicitly:

[DisableCors]
public class ControllerB1: Controller

However, ControllerB1 controller can be requested from UI anyway.

Headers in browser for B1 contoller

Request

Provisional headers are shown
Origin: http://localhost:5000
Referer: http://localhost:5000/all
User-Agent: Mozilla/5.0 AppleWebKit Chrome/69 Safari/537

Response

Request URL: http://XX.XX.XX.XX/getall
Request Method: GET
Status Code: 200 OK
Remote Address: XX.XX.XX.XX:80
Referrer Policy: no-referrer-when-downgrade
Access-Control-Allow-Origin: *
Access-Control-Expose-Headers: CustomCount        
Content-Type: application/xml; charset=utf-8
Server: Kestrel

Could you please advise how to disable CORS for specific controllers?

1 answers

3

In your example, you've done two things of note in setting up the WebHost:

  1. Created a custom CORS policy named AllowCors.
  2. Added the CORS middleware to the pipeline, which uses AllowCors as its policyName.

Here's a snippet of the Invoke function that gets called for the CORS middleware:

public async Task Invoke(HttpContext context)
{
    if (context.Request.Headers.ContainsKey(CorsConstants.Origin))
    {
        var corsPolicy = _policy ?? await _corsPolicyProvider?.GetPolicyAsync(context, _corsPolicyName);
        if (corsPolicy != null)
        {
            var corsResult = _corsService.EvaluatePolicy(context, corsPolicy);
            _corsService.ApplyResult(corsResult, context.Response);

    ...

In this snippet, _policy is null and _corsPolicyName is AllowCors. Because AllowCors is the name of a valid policy that was added using AddCors, this results in the CORS middleware applying the revelant CORS headers for all requests.

In your example, you've also used both [EnableCors(...)] and [DisableCors], which are MVC authorisation filters. By doing this, you're mostly just telling MVC to take care of CORS, which is independent of the CORS middleware you've added to the WebHost's pipeline.

This combination of MVC and CORS middleware is what is causing your unexpected results. The middleware is adding the CORS headers to your request regardless of whether or not you're asking it not to by using the [DisableCors] attribute - the CORS middleware has no idea that this MVC concept (a filter) even exists.

Based on this information, you can fix your issue in one of two ways:

  1. Remove the policyName parameter from your call to UseCors.
  2. Remove the UseCors call itself.

With option 1, the UseCors middleware will use the default policy, if it's been configured using AddDefaultPolicy on the CorsOptions passed into the AddCors delegate.

With option 2, the CORS middleware is simply excluded from the pipeline. This will also work in your example, because you've used [EnableCors(...)] where you need it. This also means that you don't need to use [DisableCors] at all - it'll default to not adding the CORS headers.

This raises the question: When would [DisableCors] be useful? As an example, consider the following basic controller:

[EnableCors("AllowCors")]
public class ExampleController : ControllerBase
{
    public IActionResult Action1() =>
        ...

    public IActionResult Action2() =>
        ...
}

It's clear that in this example, both Action1 and Action2 will set the CORS headers. If you didn't want Action2 to set the headers, you could annotate it with [DisableCors].