I'm trying very hard to understand and enable CORS in a web api project. I've hit a blocking point. I've started with an ASP.NET MVC Web Api 2 project with an ASP.NET identity. Whatever I do seems to not work.
I've deleted my global.asx file and my startup looks like this:
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
HttpConfiguration configuration = new HttpConfiguration();
// I'm not sure it this is the proper way to use webapiconfig
WebApiConfig.Register(configuration);
app.UseWebApi(configuration);
app.UseCors(CorsOptions.AllowAll);
ConfigureAuth(app);
}
}
and the WebApiConfig.Register code is:
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Configure Web API to use only bearer token authentication.
config.SuppressDefaultHostAuthentication();
config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));
config.AddODataQueryFilter();
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
var jsonFormatter = config.Formatters.OfType<JsonMediaTypeFormatter>().First();
jsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
RegisterModels(); //Automapper here
}
I have the mc aspnet cors and microsoft owin host System web installed.
The "[assembly: OwinStartup(typeof(MyProject.Startup))]" is in place, and in the web.config I have:
<appSettings>
<add key="owin:AutomaticAppStartup" value="true" />
</appSettings>
I only call app.UseCors(CorsOptions.AllowAll) to enable CORS, no other way like config.enableCors or anything else, but whenever I try getting the token or anything in the API, I get the error:
Reason: CORS header ‘Access-Control-Allow-Origin’ missing.
I have tried putting a breakpoint in the Configuration method but it is not called... ever. I'm debugging with IIS Express.
Nothing worked for me.. after many tries I finally managed to get something working.
if you have the same problem..
1) remove anything related to cors from the nugget packages installed .. everything.
2) remove anything related to cors from the web.config.
3) In Gloabal.asax
protected void Application_BeginRequest(object sender, EventArgs e)
{
var context = HttpContext.Current;
var response = context.Response;
response.AddHeader("Access-Control-Allow-Origin", "*");
response.AddHeader("X-Frame-Options", "ALLOW-FROM *");
if (context.Request.HttpMethod == "OPTIONS")
{
response.AddHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, PATCH, PUT");
response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Accept");
response.AddHeader("Access-Control-Max-Age", "1000000");
response.End();
}
}
This work for both /api and /token.
This is a generic solution please be aware before deploying it to prod.
Hope will help anyone who has the same problem.
Related
I am coding an unofficial twitter api for myself. Then I send a get to this api using the console screen in my browser with the following method.
function httpGet(theUrl)
{
var xmlHttp = new XMLHttpRequest();
xmlHttp.open( "GET", theUrl, false ); // false for synchronous request
xmlHttp.send( null );
return xmlHttp.responseText;
}
such
httpGet(https://localhost:44311/WeatherForecast/alienationxs/true);
the problem is that when i do this via www.google.com it's ok and json data reaches me. but when I do it via twitter.com I get the following error.
via google.com
my cors settings on api
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddCors(options =>
options.AddDefaultPolicy(builder =>
builder.AllowAnyHeader().AllowAnyMethod().AllowAnyOrigin())); ;
services.AddMvc();
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "twitterAPI", Version = "v1" });
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseSwagger();
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "twitterAPI v1"));
}
app.UseRouting();
app.UseCors(builder => builder
.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader());
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
all i want is to reach my api via twitter.com just like google.com.
First, let's separate the flies from the cutlets.
Cross-Origin Resource Sharing (CORS) - is a separate security layer.
Content Security Policy (CSP) - is a separate security layer, it's appied before CORS. After passing through CSP yous can face with CORS if last one is breached.
As you can see from error message "... because it violates the following Content Security Policy directive ...", you faced with CSP violation therefore your CORS settings have no mean.
What's goin on.
You enter twitter.com web page and tries to execute connect request to localhost:44311 on behalf of twitter web page. But twitter's web page protected by CSP which forbid such requests:
Pay attention on 'connect-src' directive, which governs XMLHttpRequest().
The www.google.com web page does not have CSP, therefore you request on behalf of google does success.
The Twitter API does not support CORS.
I am facing the CORS related issue when i try to connect my angular2 application and asp.net webapi application.
Error:-
register:1 Access to XMLHttpRequest at 'http://localhost:49457/api/UserDetails' from origin 'http://localhost:4200' has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header contains multiple values 'http://localhost:4200, http://localhost:4200', but only one is allowed.
Here is my code for connecting for calling asp.net webapi url through my angular2 app:-
User.service.ts
GetUser(userobj:user):Observable<User>
{
return this.http.get<User>(`http://localhost:49457/api/UserDetails`,{responseType:"text"})
.subscribe(
function(response)
{
console.log("user details retreived successfully");
},
function(error)
{
console.log(error);
});
}
This is my code for asp.net webapi,
public class UserDetailsController : ApiController
{
private sampledbEntities dbentity = new sampledbEntities();
// GET api/<controller>
public IQueryable<Userdetail> GetUserdetails()
{
return dbentity.userdetails;
}
}
Actually when i run my asp.netwebapi server it is retrieving data correctly through browser.And also i have enabled
CORS in webapiconfig.cs,
void Register(HttpConfiguration config)
{
var corsAttr = new EnableCorsAttribute("http://localhost:4200", "*", "*");
config.EnableCors(corsAttr);
}
in web.config.cs,
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="http://localhost:4200" />
<add name="Access-Control-Allow-Headers" value="Origin, Content-Type, X-Auth-Token" />
<add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, OPTIONS" />
</customHeaders>
</httpProtocol>
After enabling CORS in Webapiconfig.cs and web.config also i am facing the same error.
Please clarify how do i come out of this error,
Replace http://localhost:4200 with "*" from EnableCorsAttribute method.
void Register(HttpConfiguration config)
{
var corsAttr = new EnableCorsAttribute("http://localhost:4200", "*", "*");
config.EnableCors(corsAttr);
}
and remove httpProtocol configuration settings from web.config.
The web API from IIS 7.5 are not responding for Chrome & Firefox.
I am getting the following error in chrome
No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://10.xx.xx.xx:81' is therefore not allowed access
Firefox throw 401 unauthorized error.
Works perfectly on IE 11
Are there any additional setting required for these browsers?
First install WebApi Cors NuGet Package:
Install-Package Microsoft.AspNet.WebApi.Cors
Then in your WebApiConfig.cs file:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
var cors = new EnableCorsAttribute("*", "*", "*");
config.EnableCors(cors);
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
//other code
}
}
This way you enable CORS header globally allowing cross-site requests from any domain. If you want to allow cross-site requests from only a single (or a list of) domain, then change the constructor parameters of EnableCorsAttribute:
new EnableCorsAttribute("http://alloweddomain.com", "*", "*");
You may also apply the EnableCorsAttribute on a Controller or Action basis.
More information on the official documentation: http://www.asp.net/web-api/overview/security/enabling-cross-origin-requests-in-web-api
"A resource makes a cross-origin HTTP request when it requests a resource from a different domain than the one which the first resource itself serves"
You can use a chrome addon to allow CORS:
https://chrome.google.com/webstore/detail/allow-control-allow-origi/nlfbmbojpeacfghkpbjhddihlkkiljbi
I have CORS enabled in my web api application. and i have API controllers with both classic REST Function names like Get() and Get(string id) and a controllers with custom function names e.g.
[HttpGet]
GetSomeThing()
i have routes configured like this
config.EnableCors();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "ApiById",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
with this arrangement i get an error No 'Access-Control-Allow-Origin' header is present when i try to call controller with Classic REST functions.
e.g. /api/Controller
and if i take route with action after route without action , it gives me the same error on controller calls with custom function names.
e.g. /api/Controller/Function
please note that i have
[EnableCorsAttribute("http://localhost:xxxx", "*", "*")]
attribute on both controllers. and these calls are being made from angular application.
kindly advice.
Had the same issue. Fixed it by adding CORS headers directly to web.config. No other changes are needed.
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Methods" value="GET, POST, OPTIONS" />
<add name="Access-Control-Allow-Headers" value="content-type, accept, SOAPAction, origin" />
</customHeaders>
</httpProtocol>
</system.webServer>
Additionally, if you installed CORS via NuGet and were using a previous version of WebAPI, then you may need to uninstall it. CORS will update certain core WebAPI assemblies that may cause compatibility issues, i.e., routes not working.
And of course, you will probably want to limit the allowed origins by replacing the "*" in the Access-Control-Allow-Origin value with the URL's you want to allow.
I ran into this issue and I found it a nightmare to get cors to work.
The fix for me in the end was to remove all references to cors in my app and add just one line in the WebAPIConfig
public static void Register(HttpConfiguration config)
{
config.EnableCors(new EnableCorsAttribute("*", "*", "GET, POST, OPTIONS, PUT, DELETE, TOKEN"));
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "ActionApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "rest/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
var jsonFormatter = config.Formatters.OfType<JsonMediaTypeFormatter>().First();
jsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
var json = config.Formatters.JsonFormatter;
json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects;
config.Formatters.Remove(config.Formatters.XmlFormatter);
}
I also removed the custom headers from my web.config. Hope this help anyone else facing cors issues.
I am developing an AngularJS application calling a REST API developed with Play Framework 2.2.0.
I have a problem related to Cross-domain ajax calls as the Angular application and the Play one will not be hosted on the same domain.
Here is the JS call in my Angular service :
$http
.post("http://localhost:9001/category/list", { langCode: 'fr-FR' })
.success(function(data, status, headers, config) {
callback(data.items);
})
.error(function(data, status, headers, config) {
console.log("Error Data : " + data);
console.log("Error Status : " + status);
});
Here is the route in my Play app :
POST /category/list controllers.catalog.ProductCategoryController.list()
If I don't send any data in the request, everything works fine
If I send data, I have Ajax errors concerning ACCESS_CONTROL_ALLOW_ORIGIN, ACCESS_CONTROL_ALLOW_HEADERS
The only workaround I have is the following :
Intercept all requests in Global class and add the headers
#Override
public Action onRequest(Request request, Method method) {
return new Action.Simple() {
#Override
public Promise<SimpleResult> call(Context ctx) throws Throwable {
Logger.debug("Intercepting request and applying CORS headers...");
ctx.response().setHeader(Controller.ACCESS_CONTROL_ALLOW_ORIGIN, "*");
ctx.response().setHeader(Controller.ACCESS_CONTROL_ALLOW_HEADERS, "Content-Type");
return delegate.call(ctx);
}
};
}
Add another route with OPTIONS in routes
OPTIONS /category/list controllers.catalog.ProductCategoryController.list()
Is there a way of making the integration simpler than that ?
There's no CORS support out of the box in play; that's a situation I'd like to see changed, but for now you've identified a wart.
The good news is that you can manage a global workaround if you are OK having one CORS setting for all of your resources. It can be done in a couple of ways, one of which you identified. My inclination would be to go with a low level OPTIONS route.
Something like:
OPTIONS /*path controllers.Application.options()
From there, your handler definition can be something like:
Ok("").withHeaders(
"ACCESS_CONTROL_ALLOW_METHODS" -> "GET, POST, PUT, PATCH",
"ACCESS_CONTROL_ALLOW_HEADERS"->"Content-Type",
"ACCESS_CONTROL_ALLOW_ORIGIN" -> "*"
)
It's not super clean, but until Play adds something a bit more workable, I think it's your best option over making tons of OPTIONS routes (again, assuming you're comfortable with a global CORS setting)
You have to enable CORS support to your Play web server. The following url do have plenty of how-to for configurating server enabling the cross origin support:
http://enable-cors.org/server.html