2

I need to allow CORS requests from multiple domains from my web API. However, I do not want to let it open for all by doing below in web config.

<system.webServer>
    <httpProtocol>
        <customHeaders>
            <add name="Access-Control-Allow-Origin" value="*"/>
        </customHeaders>
    </httpProtocol>
</system.webServer>

I need to allow only a whitelist of domains to be able to make the CORS request to my APIs.

I have seen this SO question, however, I do not preferably want to use .htaccess files as I don't have control over the IIS server.

I have tried this SO answer and this blog.

The problem is, it always returns the below error.

No 'Access-Control-Allow-Origin' header is present on the requested resource.

Here's my implementation.

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
public class EnableCORSAttribute : ActionFilterAttribute
{
    private string[] origins;
    private string[] methods;

    public EnableCORSAttribute(string[] origins = null, string[] methods = null)
    {
        this.origins = origins;
        this.methods = methods;
    }

    public override void OnActionExecuted(ActionExecutedContext actionExecutedContext)
    {
        if (origins == null || !origins.Any())
        {
            //Allow all  
            HttpContext.Current.Response.AppendHeader("Access-Control-Allow-Origin", "*");
        }
        else if (origins.Contains(HttpContext.Current.Request.Url.Host, StringComparer.InvariantCultureIgnoreCase))
        {
            //Allow only if matching  
            HttpContext.Current.Response.AppendHeader("Access-Control-Allow-Origin", HttpContext.Current.Request.Url.Host);
        }

        if (methods == null || !methods.Any())
        {
            //Allow all  
            HttpContext.Current.Response.AppendHeader("Access-Control-Allow-Methods", "*");
        }
        else if (methods.Contains(HttpContext.Current.Request.HttpMethod, StringComparer.InvariantCultureIgnoreCase))
        {
            //Allow only specified  
            HttpContext.Current.Response.AppendHeader("Access-Control-Allow-Methods", HttpContext.Current.Request.HttpMethod);
        }
    }
}    

This is how I decorate my BaseController with the attribute.

[EnableCORS(origins: new string[] { "localhost" }, methods: new string[] { "GET", "POST", "OPTIONS" })]
public class BaseController : ApiController
{
    // GET api/<controller>
    public HttpResponseMessage Options()
    {
        return new HttpResponseMessage { StatusCode = HttpStatusCode.OK };
    }
}

I've also tried to register this attribute from the Global.asax file.

GlobalFilters.Filters.Add(new EnableCorsAttribute());
RegisterGlobalFilters(GlobalFilters.Filters);

But still get the same error. Not sure what else am I missing.

I have also tried Microsoft.AspNet.WebApi.Cors Nuget Package and putting this in the WebApiConfig file.

var enableCorsAttribute = new EnableCorsAttribute("http://localhost:59427",
                                   "Origin, Content-Type, Accept, Authorization",
                                   "GET, POST, OPTIONS");    
config.EnableCors(enableCorsAttribute);

It works for one domain, but as soon as I add another domain it also starts throwing the same error.

Community
  • 1
  • 1
Devraj Gadhavi
  • 3,259
  • 3
  • 34
  • 61

1 Answers1

3

It turned out to be simple than I thought and imagined.

All I needed to do is look into the request and response headers.

The other domain I was trying to add to allow CORS requests was sending some custom headers.

So I allowed those specific custom headers and it worked.

Here's the final solution.

My BaseController

// No fancy decoration here... :)
public class BaseController : ApiController
{
    // GET api/<controller>
    public HttpResponseMessage Options()
    {
        return new HttpResponseMessage { StatusCode = HttpStatusCode.OK };
    }
}

My WebApiConfig

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        //Some API routes here...

        var enableCorsAttribute = new EnableCorsAttribute(
            // Comma separated whitelist of allowed domains, notice no slash ('/') at the end of domain
            "http://local.ui.two:9003,http://local.ui.one:9001", 
            // Allowed Custom Headers
            "Origin, X-Requested-With, Content-Type, Accept, Authorization, Cache-Control, If-Modified-Since, Pragma",
            // Allowed methods
            "GET, PUT, POST, DELETE, OPTIONS"
        );

        config.EnableCors(enableCorsAttribute);
    }
}

And registered this WebApiConfig in Global.asax.

protected void Application_Start()
{
    GlobalConfiguration.Configure(WebApiConfig.Register);
}
  • Nothing required in web.config
  • No custom fancy attribute needed to be written, why re-invent the wheel!? :)
  • Only using Nuget Package Microsoft.AspNet.WebApi.Cors

This other question that I asked and two geniuses that stood up to help the fellow community, gave me the correct direction.

Community
  • 1
  • 1
Devraj Gadhavi
  • 3,259
  • 3
  • 34
  • 61