I have an ASP.NET web API that is being called by three different SPA. I am using windows authentication for the web API. I initially tried to configure CORS in the Web.config l
Create custom attribute using ICorsPolicyProvider
something like following to check if the requested origin is allowed or not
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method,AllowMultiple = false)]
public class EnableCorsForAPIKeysAttribute :
Attribute, ICorsPolicyProvider, IFilter
{
public async Task<CorsPolicy> GetCorsPolicyAsync(
HttpRequestMessage request, CancellationToken cancellationToken)
{
var corsRequestContext = request.GetCorsRequestContext();
var originRequested = corsRequestContext.Origin;
if (await IsValidOrigin(originRequested)) //Check if requested origin is valid or not
{
// Grant CORS request
var policy = new CorsPolicy
{
AllowAnyHeader = true,
AllowAnyMethod = true
};
policy.Origins.Add(originRequested);
return policy;
}
else
{
// Reject CORS request
return null;
}
}
public bool AllowMultiple { get {return false;} }
}
To use it, add it to your API controller
[EnableCorsForAPIKeys]
public class APIBaseController : ApiController
{
}
I was able to solve my problem by further customizing the Application_BeginRequest method in Global.asax.cs, like this:
protected void Application_BeginRequest()
{
if (Request.HttpMethod == "OPTIONS")
{
Response.StatusCode = (int)HttpStatusCode.OK;
Response.AppendHeader("Access-Control-Allow-Origin", Request.Headers.GetValues("Origin")[0]);
Response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Accept");
Response.AddHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
Response.AppendHeader("Access-Control-Allow-Credentials", "true");
Response.End();
}
}
What this code does is add the missing headers to the OPTIONS response (preflight request) that were causing the preflight error. Since I have different origins calling my web API, I'm using Request.Headers.GetValues("Origin")[0])
to set the origin in the response dinamically.
In the WebApiConfig.cs I still specified the different origins but used wildcards on the headers and methods, as well as setting the SupportsCredentials
to true, like this:
var cors = new EnableCorsAttribute("http://localhost:63342,http://localhost:63347,http://localhost:63345", "*", "*");
cors.SupportsCredentials = true;
config.EnableCors(cors);
Also, if you're using AngularJS like I am, you must configure $http to use credentials. This can be configured globally like this:
angular
.module('Application')
.config(['$httpProvider',
function config($httpProvider) {
$httpProvider.defaults.withCredentials = true;
}
]);
And that's it. This solved my problem. If someone else is still having problems, I recommend reading the following publications, which helped me reach my answer: