Using Chrome developer tools.I am getting a cancelled status on a request to a WEB API resource.(network tab)
Server : WEB API 2.1
Client: Angular $http request
The initial message referred to a CORS violation as the cause. I enabled CORS on the server.
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
//Going camel case in Web API http://frankapi.wordpress.com/2012/09/09/going-camelcase-in-asp-net-mvc-web-api/
var jsonFormatter = config.Formatters.OfType<JsonMediaTypeFormatter>().First();
jsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
// cors support
var cors = new EnableCorsAttribute( "http://localhost:9168/", "*", "*");
config.EnableCors();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
// Uncomment the following line of code to enable query support for actions with an IQueryable or IQueryable<T> return type.
// To avoid processing unexpected or malicious queries, use the validation settings on QueryableAttribute to validate incoming queries.
// For more information, visit http://go.microsoft.com/fwlink/?LinkId=279712.
//config.EnableQuerySupport();
}
}
After CORS was implemented, I am still getting cancelled a response message on the API calls, however, when drilling into the message, the data is being returned from the server.
I checked Fiddler and the request header is passing the origin etc correctly, however I am still getting this error:
XMLHttpRequest cannot load http://localhost:4416/api/LookupTrades. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:9168' is therefore not allowed access.
There seems to be loads of posts about the cancelled status in chrome, all with different causes. Not sure what to do next. Any ideas?
install a Nuget package `"Microsoft.AspNet.WebApi.Cors" (version="5.1.0")
Add following line in your WebApiConfig.cs file
config.EnableCors(new EnableCorsAttribute("*", "*", "*"));
you can also set this property in your js file before ajax call
$.support.cors = true;
Related
I am using oauth2 in springboot for the server side and React application on the Client. I am sending the token request for the grant_type client_credentials to /oauth/token from react application and get the Above error.
I have used #CrossOrigin and also used http.cors() for the global security config but still keep seeing the Preflight cors block error in browser console.
Error:
Access to XMLHttpRequest at 'http://localhost:8000/oauth/token' from
origin 'http://localhost:3000' has been blocked by CORS policy:
Response to preflight request doesn't pass access control check: It
does not have HTTP ok status. xhr.js:177 POST
http://localhost:8000/oauth/token net::ERR_FAILED
I think the main cause of the error is already highlighted in the error itself.
Response to preflight request doesn't pass access control check.
It means that spring security is in the picture for the preflight request and as pre-flight request doesn't contain any information about the authentication so spring security treat this request as coming from unauthenticated client and hence reject it.
You've to make ensure that CORS is handled first and you can achieve this by using the CorsFilter. You can use the CorsFilter with Spring Security by providing a CorsConfigurationSource using the following
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.cors().and()
...
}
#Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
// You can restrict the origin and method in the following stmt according to the requirement
configuration.setAllowedOrigins(Collections.singletonList(CorsConfiguration.ALL));
configuration.setAllowedMethods(Arrays.asList("HEAD", "GET", "POST", "PUT", "DELETE", "PATCH"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}
https://www.youtube.com/watch?v=7Yqb275FKmY helped me up. The issue was the #Order(Ordered.HIGHEST_PRECEDENCE) on my SimpleCORSFilter class that implements filter class.
So I have an angular cli app with Angular 4 talking to a new .NET Core API project. My environment is Windows 7 and the standard browser used in my organisation is IE 11 (so ultimately needs to work with this, however I want to develop in Chrome or FF as TypeScript / .map files don't work on Windows 7). It's an internal web application and we need to use Windows authentication. I created the .NET Core app with Visual Studio 2017 Community.
TL;DR My problem is that I continually get CORS errors in Chrome and FF, even after hitting the api and successfully returning data from the back end. The bizarre thing is that Chrome and FF successfully call the api when I don't enable CORS on the .NET side. When I try to enable CORS Chrome or FF don't hit the api at all. In either case the client code calls an error handler regardless of whether it can connect to the api or not.
So here's the .NET code I tried (although Chrome and FF both call the api without this). I created a CORS policy in Startup.cs\ConfigureSevices with AllowAnyOrigin and also tried the specific "http://localhost:4200" url (local server the app runs on). Also various combinations of AllowAnyMethod and AllowAnyHeader.
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options =>
{
options.AddPolicy("MyPolicy",
builder =>
{
builder.WithOrigins("http://localhost:4200")
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials();
});
});
//...
}
I added the CORS policy globally in Startup.cs\Configure.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
app.UseCors("MyPolicy");
// ...
}
I also tried adding it to the Controller directly as an attribue using [EnableCors]
[Route("api/[controller]")]
[EnableCors("MyPolicy")]
public class CustomerController : Controller
Here's the method on the controller:
// GET: api/customer/id
//[Authorize]
//[EnableCors("MyPolicy")]
[HttpGet("{id}")]
public async Task<IActionResult> Get(int id)
{
var customer = await _customerService.GetAsync(id);
if (customer == null)
{
return NotFound();
}
string msJson = JsonConvert.SerializeObject(customer,
JsonCustomSettings.CustomJsonSettings);
return Ok(msJson);
}
I also read that I need to add the withCredentials option to the api call in Angular - here's the Angular code:
getContent(Id: number): Promise<Client[]> {
const headers = new Headers({'Content-Type': 'application/json'});
const options = new RequestOptions({ headers: headers, withCredentials: true });
console.debug('In getContent:' + id);
return this.http.get("http://localhost:13751/api/customer/"+id, options)
.toPromise()
.then(res => this.extractData(res))
.catch(this.handleError);
}
Results:
In Chrome and FF "this.handleError" always gets called. As I said Chrome and FF both call the api and return data successfully when I remove the CORS settings from the api.
When I add any of the CORS options on the .NET side in Startup.cs and / or on the controller and put a break point in the controller code:
no error in IE 11 (however I get other TypeScript errors and can't debug due to the lack of .map files on Windows 7)
Chrome or FF don't hit the api at all, both return CORS errors (see below for errors):
When I disable all CORS settings on the api side:
no error in IE 11
Chrome and FF both hit the api and data are returned from my service. However "this.handleError" is always called and I get the CORS errors in the browser / TS code when the call returns:
====
Chrome error:
XMLHttpRequest cannot load http://localhost:13751/api/customer/2518. Response to preflight request doesn't pass access control check: A wildcard '*' cannot be used in the 'Access-Control-Allow-Origin' header when the credentials flag is true. Origin 'http://localhost:4200' is therefore not allowed access. The credentials mode of an XMLHttpRequest is controlled by the withCredentials attribute.
FF error:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:13751/api/customer/2518. (Reason: CORS header 'Access-Control-Allow-Origin' missing)
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:13751/api/customer/2518. (Reason: CORS request failed).
====
So I really don't understand why I'm getting the CORS error in Chrome and FF when I can step through the code on the api side and data is returned to the client. (I also have the "Allow-Control-Allow-Origin" plugin for Chrome but this doesn't seem to make a difference).
Would be great if someone could shed some light on this.
Do you set the "Access-Control-Allow-Origin" header to the api response?
If not, here's a way of doing that:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
app.UseCors("MyPolicy");
// ... add api and other stuff
//Add a middleware which sets the header on the response
app.Use(async (context, next) =>
{
// Add Header
context.Response.Headers["Access-Control-Allow-Origin"] = "*";
// Call next middleware
await next.Invoke();
});
}
Cross origin requests are blocked by default because of the browser security policies. To allow CORS requests in Google Chrome install this plugin : https://chrome.google.com/webstore/detail/allow-control-allow-origi/nlfbmbojpeacfghkpbjhddihlkkiljbi?utm_source=chrome-ntp-icon
You will see an icon at top right corner of chrome. Turn on Cross origin resource sharing and then try it out.
I have an angular app that sends an http request to my Service Fabric Web API (deployed on a Secure Service Fabric cluster) like so:
$scope.request_headers = {
"Content-Type": "application/xml; charset=utf-8",
"Access-Control-Allow-Origin":"*"
}
$http({
url: "Service_Fabric_web_api_url",
method: "GET",
headers:$scope.request_headers
}).
then(function (result) {
console.log(result);
});
I've also enabled CORS globally in my web api startup class like so:
HttpConfiguration config = new HttpConfiguration();
var cors = new EnableCorsAttribute("*", "*", "*");
config.EnableCors(cors);
When I run my angular app locally and try sending the http request, I still get this error:
XMLHttpRequest cannot load Service_Fabric_web_api_url. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:xxxxx' is therefore not allowed access. The response had HTTP status code 500.
I'm able to access my service directly from my browser with the same url.
Also, the same http request works when I tried deploying my Web Api on an unsecure Service Fabric Cluster with the same lines added to the startup class to enable CORS.
Why is this happening even though I've enabled CORS globally in my Web API and particularly when its on a secure cluster?
In your Startup.cs class, do you have this line? :
public void ConfigureAuth(IAppBuilder app)
{
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
}
There are also a couple NuGet packages associated with Cors:
<package id="Microsoft.AspNet.Cors" version="5.0.0" targetFramework="net45" />
<package id="Microsoft.Owin.Cors" version="3.0.1" targetFramework="net45" />
The CORS message is a red herring. If you look at the end of the error message you'll see this:
The response had HTTP status code 500.
Usually the response will include some detail about the error. I suggest using a tool like Fiddler with HTTPS decryption enabled so you can see the content of the response.
I am building an app with Spring-boot (on http://localhost:8080) and angular (on http://localhost:80).
the frontend and backend code are served by 2 different servers. In order to avoid CORS problems, I used to put in place an intermediate nginx server but I am not satisfied with this solution anymore. Hence, I have to allow CORS.
I allowed CORS globally with those lines :
#Configuration
public class WebMvcConfiguration extends WebMvcConfigurerAdapter {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("http://localhost")
.allowCredentials(true)
;
}
}
This works for every routes except for the authentication route which is handled with Spring security :
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
http
.formLogin()
.successHandler(successHandler())
.failureHandler(failureHandler())
//[...]
}
private AuthenticationSuccessHandler successHandler() {
return (httpServletRequest, httpServletResponse, authentication) ->
httpServletResponse.setStatus(HttpServletResponse.SC_OK);
}
private AuthenticationFailureHandler failureHandler() {
return (httpServletRequest, httpServletResponse, e) -> {
httpServletResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
};
}
Here is the code that sends the request on the frontend part :
$http.post('http://localhost:8080/api/login', $.param({'username': username, 'password': password}),
{headers: {'content-type': 'application/x-www-form-urlencoded'}}
).then(function() {})
.catch(function(error) {};
If I enter the correct password, the http response code (that I can see in the Chrome console) is 200 but I still reach the catch block (with error.status = -1) and I can see this error message in the console :
XMLHttpRequest cannot load http://localhost:8080/api/login. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost' is therefore not allowed access.
If I enter the wrong password I also reach the catch block with this error message :
XMLHttpRequest cannot load http://localhost:8080/api/login. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost' is therefore not allowed access. The response had HTTP status code 401.
I also notice that CORS response headers are missing when I call the authentication endpoint.
Any ideas?
EDIT : it works if I manually add headers in the custom success handler. I would prefer if Spring-security could take into account the global CORS configuration.
From my experience you'll need to include the port number in CORS, the error message from the browser is a bit misleading.
You can verify that by inspecting network and check the Origin field of your request headers. The value in Access-Control-Allow-Origin of your response headers must match that exactly including protocol and port.
You should take a look on Spring website. There are solutions for consuming web service and managing CORS :
Enabling Cross Origin Requests for a RESTful Web Service : https://spring.io/guides/gs/rest-service-cors/
Consuming a RESTful Web Service with AngularJS : https://spring.io/guides/gs/consuming-rest-angularjs/
Had the exact same issue two thing you could do,
#CrossOrigin(origins = "http://localhost:8080") add this to the service methods. The idea behind this is you enable CORS request through your service itself.
Use JSONP, but this has certain limitation. Also i wasnt successful in implementing it, so i used the above option.
I have a web api 2 app which I call to using an angularjs client. The web api app is capable of issuing access tokens and refresh tokens for authentication.
Having the following lines in the "GrantResourceOwnersCredentials" method, the CORS is working fine for allowing to issue access tokens:
var allowedOrigin = context.OwinContext.Get<string>("as:clientAllowedOrigin");
if (allowedOrigin == null) allowedOrigin = "*";
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { allowedOrigin });
However, when I try to issue refresh tokens through the angularjs app, I get this good old error in the console:
OPTIONS http://localhost:65141/token
(index):1 XMLHttpRequest cannot load http://localhost:65141/token. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:56815' is therefore not allowed access. The response had HTTP status code 400.
I was wondering as the access tokens are being issued fine, and the refresh tokens are also issued using the same endpoint, what should I do to overcome this issue?
By the way, the angular code is fine. I disabled google chrome web security and then everything worked! Any help is greatly appreciated!
After searching the whole freaking internet, here is what I found that resolves the problem. Adding this code to the AuthorizationProvider will resolve the problem:
public override Task MatchEndpoint(OAuthMatchEndpointContext context)
{
if (context.IsTokenEndpoint && context.Request.Method == "OPTIONS")
{
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Headers", new[] { "authorization" });
context.RequestCompleted();
return Task.FromResult(0);
}
return base.MatchEndpoint(context);
}