I have a RESTfull Backend implemented with Spring security running on localhost:8080, a Login filter responds to login requests with a token placed in the headers, I didn’t even implemented an Endpoint method for that, It is all done by Spring Security magic by the following line of code:
protected void configure(HttpSecurity http) throws Exception {
// disable caching
http.headers().cacheControl();
http.csrf().disable() // disable csrf for our requests.
.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/login").permitAll()
.anyRequest().authenticated()
.and()
// We filter the api/login requests
.addFilterBefore(new JWTLoginFilter("/login", authenticationManager()), UsernamePasswordAuthenticationFilter.class)
…
The frontend is a Angularjs Nodejs NPM Bower project running a static http server on localhost:8000. On frontend I make a simple POST request as follows:
$scope.login = function () {
var data = {
"username":$scope.username,
"password":$scope.password
}
$http({
url: baseUrl,
method: "POST",
data: data
}).then(function (response) {
console.log("###### SUCCESS #####");
var headers = response.headers();
console.log("headers: "+JSON.stringify(headers));
var token = headers.authorization.split(" ")[1];
console.log("token: "+token);
$http.defaults.headers.common['Authorization'] = token;
$location.path("/view1");
}, function (responseData) {
// called asynchronously if an error occurs
// or server returns responseData with an error status.
console.log("###### FAIL #####");
console.log("Response: "+JSON.stringify(responseData));
$window.alert("Failed to Login");
});
This works like a charm in IE (also with curl, wget and python requests) but it miserably failing on Chrome and Safary.
I know that those Browsers are blocking CORS POSTs, making the request empty as soon as the reach the backend, in fact I don’t see any data when I log out the request from backend. I tried every possible combination of:
Frontend side:
1) $http(method: POST)
2) $http.post(
3) Adding flags: Access-Control-Allow-Origin, Access-Control-Expose, etc.
4) Adding all possible header combination: ‘Content–Type’:’application/
Browser side:
1) Start chrome with flag: --disable-web-security
2) Installing Chrome extension CORS
Backend side:
1) Spring Security Disable csfr
2) Spring Security Permit all
3) Spring Security HttpMethod.OPTION
Nothing, NHOTING worked for me!
is there something I’m missing?
Is there another way to send POST requests?
EDIT
As discussed, I modified the classes as follow:
WebSecurityConfig:
.antMatchers("/login").permitAll()
.anyRequest().authenticated()
.and()
// We filter the api/login requests
.addFilterBefore(new JWTLoginFilter("/login", authenticationManager()), UsernamePasswordAuthenticationFilter.class)
.addFilterBefore(new CORSFilter(), BasicAuthenticationFilter.class)
and implemented the CORSFilter as suggestet.
I also add the WebConfig class as suggested:
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedOrigins("http://localhost:8000")
.allowedMethods("PUT", "POST");
}
}
Because of the empty string the login filter throws:
com.fasterxml.jackson.databind.JsonMappingException: No content to map due to end-of-input
this will be chatched by spring security which denied the access.
I also triyed to move the frontend server on other ports then 8000 (4200, 7000, etc.) with no success.
See Question&Answers more detail:
os