How to enable Cors in ASP.NET Web Api - angularjs

I'm learning Angular 2. This is my service that's supposed to pull data from an ASP.NET Web api application.
#Injectable()
export class ExpenseService {
private _expUrl = "http://localhost:65400/api/expenses";
constructor(private _http: Http){}
getExpenses(): Observable<IExpense[]> {
return this._http.get(this._expUrl)
.map((response: Response) => <IExpense[]>response.json())
.do(data => console.log('ALL: ' + JSON.stringify(data)))
.catch(this.handleError)
}
//more here...
}
The above code is working fine in Microsoft Edge. However, in Chrome and FireFox, I'm getting the following error:
XMLHttpRequest cannot load http://localhost:65400/api/expenses.
No 'Access-Control-Allow-Origin' header is present on the requested resource.
Origin 'http://localhost:3000' is therefore not allowed
I've enabled CORS in my web api as suggested by many posts.
public void ConfigureServices(IServiceCollection services)
{
services.AddCors();
//...
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env,
ILoggerFactory loggerFactory)
{
//...
app.UseCors(builder =>
builder.WithOrigins("http://localhost:3000/"));
}
That didn't change the outcome. I'm still getting the same error in Chrome and FireFox while Edge is working just fine.
Thanks for helping

CORS is something that are enforced by the client, supported by the server.
CORS is there to help you as a user. It restrict the possibility for a client, like javascript on host google.com, to call a service on mydomain.com. This is a cross-domain call, which Chrome and FireFox does not allow. (Would assume that Edge also supported this). If you are hosting a service and client on some host and port, CORS is not used.
A service must define which host from a cross-domain is allowed. This can either be from all or from a specific host.
To allow access from all host do the following:
Configuration
public void ConfigureServices(IServiceCollection services)
{
services.AddCors();
}
Controller
[EnableCors("AllowSpecificOrigin")]
public class TestController : ApiController
If your service is a public service, be aware of the consequences.
You can read more here: https://learn.microsoft.com/en-us/aspnet/core/security/cors

Related

Enabling CORS in Google App Engine Flexible Environment

I am facing issues enabling CORS support for a ASP.NET CORE application that is hosted using Google App Engine and the flexible environment.
Every AJAX request using the axios library results in the following error...
Access to XMLHttpRequest at 'https://api.[something].services/request'
from origin 'http://localhost:8080' has been blocked by CORS policy:
No 'Access-Control-Allow-Origin' header is present on the requested
resource.
Here the configuration of CORS on the web api:
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options =>
options.AddPolicy("MyPolicy",
builder =>
{
builder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials();
}));
// ...
services.AddMvc();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
System.Environment
.SetEnvironmentVariable("GOOGLE_APPLICATION_CREDENTIALS",
Path.Combine(Directory.GetCurrentDirectory(),
Configuration["GAE:Credentials"]));
}
else
{
app.UseHsts();
}
// ...
app.UseCors("MyPolicy");
app.UseHttpsRedirection();
app.UseMvc();
}
This type of CORS errors are usually obtained when a resource1 does cross-origin HTTP requests to another resource2 without the handler for resource2 returning an Access-Control-Allow-Origin: response header containing the value http://resource1.
With this in mind, the http header handler configuration needs to be appropriately set in the application App.yaml file which is deployed in App Engine. Most browsers use the XMLHttpRequest object to make a cross-domain request,taking care of inserting the right headers and handling the CORS interaction with the server.
All these information above apply to App Engine Standard and not the App Engine Flex environment. That is because CORS requests are disallowed by default on App Engine Flex. However you can allow CORS request by adding this "x-google-endpoints" to your API configuration documentation.

Keycloak CORS issue associated with login redirect

Similar questions here and here have not helped me resolve the problem.
I am using Keycloak 4.4.0 to secure my REST service, which is implemented using Spring Boot and I am using React for the front end.
I get a CORS error when the front end (running on localhost:3000) makes an API call to localhost:8080/login and is redirected to the Keycloak login page.
The error is:
localhost/:1 Failed to load http://localhost:8080/login: Redirect from 'http://localhost:8080/login' to 'http://localhost:9080/auth/realms/hbs/protocol/openid-connect/auth?response_type=code&client_id=hbs&redirect_uri=http%3A%2F%2Flocalhost%3A8080%2Flogin&state=ab5034a9-4baa-4be3-9ec1-feefbe5f9c0b&login=true&scope=openid' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access.
I have added a single value of '*' to the Web Origins config section in the Keycloak client.
I have annotated my REST controller as follows:
#RestController
class MyController
{
#CrossOrigin
#GetMapping("/login")
public ResponseEntity<Foo> getFoo(Principal principal)
{
return ResponseEntity.ok(new Foo("blah"));
}
}
I have enabled Keycloak and CORS in the application properties:
keycloak.cors = true
keycloak.enabled = true
If I disable Keycloak and CORS, problem goes away.
As described here, I suspect the issue is to do with the Keycloak server not responding with any Access-Control-Allow-Origin headers despite Web Origins being correctly configured in the Keycloak admin portal. But I'm not completely sure how to confirm this.
Imagine the following json below is your Keycloak configuration:
{
"realm" : "cors",
"resource" : "cors-database-service",
"auth-server-url": "http://localhost-auth:8080/auth",
"bearer-only" : true,
"ssl-required": "external",
"enable-cors": true
}
Try adding the last line to your configuration file.
Let me know if it worked for you!
OBS: I'm facing the same issue, but I'm using Wildfly/JBOSS adapters and making this configuration inside the application server.
#EDIT:
This worked fine for me.
Try changing the "Access Type" to bearer-only inside your REST Client on Keycloak.
Also, don't forget to add the parameter {"{"Authorization" : "bearer " + $TOKEN} when sending HTTP requests from your client to your RESTful API.
For those encountering this error with spring. Just add this class to your project to allow cors:
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
#Configuration
public class CorsConfig implements WebMvcConfigurer {
String[] origins = new String[] { "http://localhost:8081"};
#Override
public void addCorsMappings(CorsRegistry registry) {
System.out.println("TEST TEST");
registry.addMapping("/**")
.allowedOrigins("*");
// .allowedOrigins(origins);
}
}
The asterisk allows all origins, which may not be secure for productive systems. A string array can be used to specify more than one origin.

CORS error from .NET Core web api even after successfully calling the api

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.

CORS problems with Spring-security

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.

CORS issue with Angular Client and ASP.NET Web API

I have a client side application built with AngularJS that is consuming services from a RESTful ASP.NET Web API. So far so good. I have created both of them under the same solution on Visual Studio, the API is an ASP.NET project and the AngularJS is a website. Both projects have to work using windows authorization so I created the API with windows authorization as the default AA mechanism in the project creator wizard, and for the AngularJS I have enable windows authentication on the properties tab of the project.
In order to test the communication between the two applications I decided to build a simple service. I created a Quotation model class, built the controller for it, and then added migrations and added some quotations in the database. I then tried to send a get request from the angular application only to receive this error:
After studying this issue I realized that I had to enable CORS on the web API. So I went to NuGet Package Manager and added the Microsoft.AspNet.Cors package to the project.
I then enabled CORS on the WebApiConfig.cs like this:
namespace Web_API
{
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Web API routes
config.MapHttpAttributeRoutes();
config.EnableCors();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
}
And I added the header to my controller class and method (just in case on the class wasn't enough):
namespace Web_API.Controllers
{
[EnableCors("*", "*","*")]
public class QuotationsController : ApiController
{
private Web_APIContext db = new Web_APIContext();
// GET: api/Quotations
[EnableCors("*", "*", "*")]
public IQueryable<Quotation> GetQuotations()
{
return db.Quotations;
}
However, I still get the same error when I make a get request from the AngularJS application. Does anyone know how to fix this issue?
can you please try this:
[EnableCors(origins: "*", headers: "*", methods: "*")]
Also don't use EnableCors in your method. As you've used this on your controller, by default all methods will fall under this rule.
I hope this will solve your problem. Thanks.

Resources