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.
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.
I am working on an update functionality using PUT. I have a React front end and Spring back-end API. Here is the following PUT request made from front-end:
updateStuff(username, id, stuff){
return Axios.put(`http://localhost:8080/stuff/${username}`, {stuff})
}
Controller to handle this request:
#RestController
#CrossOrigin(origins="http://localhost:3000")
public class StuffController {
#Autowired
private StuffService stuffService;
#PutMapping(path="/stuff/{username}/{id}")
public ResponseEntity<Stuff> updateStuff(#PathVariable String username,
#PathVariable long id,
#RequestBody Stuff stuff) {
Stuff response = stuffService.save(stuff);
return new ResponseEntity<Stuff>(stuff, HttpStatus.OK);
}
I am able to use the same service for GET and DELETE. I am also able to send request using REST client. But when I am trying using browser I am getting this error in console:
Access to XMLHttpRequest at 'http://localhost:8080/stuff/abc' from origin
'http://localhost:3000' has been blocked by CORS policy:
Response to preflight request doesn't pass access control check: No 'Access-
Control-Allow-Origin' header is present on the requested resource.
PUT http://localhost:8080/stuff/abc net::ERR_FAILED
Not able to figure out why its just happening for PUT request? How to resolve this? Appreciate your help and time!
EDIT:
Updated the front-end to:
updateStuff(username, id, stuff){
return Axios.put(`http://localhost:8080/stuff/${username}`, {
headers:{
'Access-Control-Allow-Origin':'*',
'Content-Type': 'application/json;charset=UTF-8',
}
})
}
Still its throwing the same error. So far Spring Security is not configured. I am just checking a simple update flow without any authentication or authorization.
EDIT 2: Request headers in browser has Access-Control-Allow-Origin: *:
I ran into a similar issue a while ago. Check if the variables of your model class in the backend have the same name as in your frontend. That fixed it for me.
The best way to deal with this cors policy is to add a proxy field in the pakage.json file.enter image description here
In reactjs application you can use your spring boot api's URL as proxy to avoid CORS issue.
package.
package.json
{
"proxy": "http://localhost:8080/",
"dependencies": {
.
.
.
}
}
axios
Axios.put(stuff/${username}, {stuff})
I'm trying to use react-admin in my project, which requires Content-Range.
So in my server I have written :
#GetMapping("admin/user")
ResponseEntity<List<User> > getAll()
{
System.out.println(new Date());;
HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.set("Content-Range",
"posts 0-"+userRepository.findAll().size()+"/"+userRepository.findAll().size());
return ResponseEntity.ok()
.headers(responseHeaders)
.body(userRepository.findAll());
}
Also configured CORS :
#Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry
.addMapping("/**")
.allowedOrigins("http://localhost:3000");
registry
.addMapping("/admin*")
.allowedOrigins("http://localhost:3001")
.exposedHeaders("Content-Range");
}
};
}
Error : Access to fetch at 'http://localhost:8080/admin/user?filter=%7B%7D&range=%5B0%2C9%5D&sort=%5B%22id%22%2C%22ASC%22%5D' from origin 'http://localhost:3001' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
Why am I getting this error ?
Working fine on postman:
Later I even added : responseHeaders.set("Origin", "http://localhost:3001");
Still no hope.
How this can be resolved ?
This is cros error causing by browser.
You can configure your proxy with your react app package.json file just add
"proxy" : "http://localhost:8080"
Now you just need to provide relative path to your api request
Example : '/admin/user/' // your app going to make request to http://localhost:8080/admin/user
And also make sure you are allowing right url of your back-end
registry
.addMapping("/**")
.allowedOrigins("http://localhost:3000"); // make sure this is right url of your frontend
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.
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