Invalid CORS request for post call? - java

Request URL: ******
Request Method: OPTIONS
Status Code: 403
Remote Address: ****
Referrer Policy: no-referrer-when-downgrade
For the post call browser showing it as OPTIONS.
The following is the server code:
#Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurerAdapter() {
#Override
public void addCorsMappings(CorsRegistry registry) {
System.out.println("onboard cors");
registry.addMapping("/**").allowedMethods("GET", "PUT", "POST", "DELETE", "OPTIONS").allowedOrigins("*").allowedHeaders("*");
}
};
}
The above code is working fine when I directly call the respective service.
But getting 'invalid cors request' error by calling the service through zuul api gateway.
Any suggestions plz?

Your browser first checks if POST method is safe to send to the endpoint and if yes then does POST request. You should provide permissions to OPTIONS method and respond it with Allow: GET, HEAD, POST and all should be okay. I faced that problem while working with Python, so it's all about CORS and does not depend on platform.
See more information about it here

The following solution worked for me.
Add the below code in zuul project:
#Bean
public FilterRegistrationBean corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
source.registerCorsConfiguration("/**", config);
FilterRegistrationBean bean = new FilterRegistrationBean(new org.springframework.web.filter.CorsFilter(source));
bean.setOrder(0);
return bean;
}
Adding corsfilter code in all microservices is not required.
Reference: https://stackoverflow.com/a/46277194/4132466

Related

React can't get any response from spring boot after fetch request

I'm trying to fetch data from post request in react, but I can't get nothing back, the response it's ok and save the data in the database, after that I need to return a token in react but I can't understand why It does't work.
I tried a lot ot cros but nothing change.
Here the request in react:
save(registerDTO) {
fetch('http://localhost:8080/api/auth/register',{ method: 'POST', headers: { 'Content-Type': 'application/json', 'Accept': '*/*', 'Access-Control-Allow-Credentials': true},body: JSON.stringify( registerDTO )})
.then(data => console.log(data))
.catch(error=>console.warn(error))
}
}
In the ispection on google chrome everything works but I can't see the response even on there
there isn't nothing in the response option.
This is my code on spring boot side:
#PostMapping("/register")
public ResponseEntity<Map<String,String>> registerHandler(#RequestBody RegisterDTO registerDTO) {
log.info("User: {}",registerDTO);
return ResponseEntity.ok(registerService.saveUser(registerDTO));
}
In postman everything work fine, I can't even get the error message in react.
I tried to add a lot of cors code:
#Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("http://localhost:3000","192.168.1.7:3000"));
configuration.setAllowedMethods(Arrays.asList("GET","POST","DELETE"));
configuration.setAllowedHeaders(Arrays.asList("*"));
configuration.setAllowCredentials(true);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
// #Bean
// public WebMvcConfigurer corsConfigurer() {
// return new WebMvcConfigurer() {
// #Override
// public void addCorsMappings(CorsRegistry registry) {
// registry.addMapping("/**").allowedOrigins("http://localhost:3000/**");
// }
// };
// }
// #Bean
// public CorsConfigurationSource corsConfigurationSource() {
// UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
// source.registerCorsConfiguration("/**", new CorsConfiguration().applyPermitDefaultValues());
// return source;
// }
and I added this annotation in the restcontroller:
#CrossOrigin(origins = "http://localhost:3000")
you missing:
.then(res=> res.json())
in your fetch code.

Not able to read cookies in Angular from API response (Spring Boot Service) - Cannot read properties of null (reading 'headers')

Service Code
public ResponseEntity<String> getSessionCookie() {
logger.info("Get Cookies");
var cookie1 = ResponseCookie.from("ASP.NET_SessionId_Wx", appConfig.getSessionId()).httpOnly(false).path("/").secure(false).build();
var cookie2 = ResponseCookie.from("WX-XSRF-TOKEN", appConfig.getToken()).httpOnly(false).path("/").build();
return ResponseEntity.ok().header(HttpHeaders.SET_COOKIE, cookie1.toString())
.header(HttpHeaders.SET_COOKIE, cookie2.toString()).build();
}
Angular Code
Service
public getSession(): Observable<any> {
return this.http.get<any>('//example.com/getSessionCookie/', {withCredentials: true});
}
Component
this.ds.getSession().subscribe((res) => {
console.log('Get Session Header: ', res.headers);
})
}
Able to view the cookies in Postman and Chrome Dev Tools (Network tab - Response Headers)
Added CORS config to SprinBoot App
public class CorsConfiguration implements WebMvcConfigurer
{
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedOriginPatterns("*").allowedHeaders("*").allowCredentials(true)
.allowedMethods("GET", "POST", "PUT", "DELETE");
}
}
I figured it out.
The issue was with the 'Set-Cookie'.
Angular is unable to read the 'Set-Cookie' header. Changed the header key to some other name and added the same in exposedHeaders as well.
Worked like a Charm:).
Thanks.

No 'Access-Control-Allow-Origin' header is present (CORS) - Spring Boot (Spring security) Microservices + Vue.js

I'm working on Spring Boot project based on microservices architecture on backend and Vue.js on frontend.
Structure of my project is next:
For avoiding CORS error usually I add #CrossOrigin annotation on to class and it works.
It was all good and has been working well, until I added security part with ability to login users.
What did I did:
1. To API Gateway that built on spring-cloud-gateway I've added AuthFilter that uses as interceptor to create and check JWT:
api-gateway/src/main/java/.../AuthFilter.java
#Component
public class AuthFilter extends AbstractGatewayFilterFactory<AuthFilter.Config> {
private final WebClient.Builder webClientBuilder;
#Autowired
public AuthFilter(WebClient.Builder webClientBuilder) {
super(Config.class);
this.webClientBuilder = webClientBuilder;
}
#Override
public GatewayFilter apply(Config config) {
return (exchange, chain) -> {
if(!exchange.getRequest().getHeaders().containsKey(HttpHeaders.AUTHORIZATION)) {
throw new RuntimeException("Missing auth information");
}
String authHeader = exchange.getRequest().getHeaders().get(org.springframework.http.HttpHeaders.AUTHORIZATION).get(0);
String[] parts = authHeader.split(" ");
if(parts.length != 2 || !"Bearer".equals(parts[0])) {
throw new RuntimeException("Incorrect auth structure");
}
return webClientBuilder.build()
.post()
.uri("http://manager-service/api/v1/auth/validateToken?token=" + parts[1])
.retrieve()
.bodyToMono(EmployeeDTO.class) //EmployeeDTO.class is custom DTO that represents User
.map(user -> {
exchange.getRequest()
.mutate()
.header("x-auth-user-id", user.getId());
return exchange;
}).flatMap(chain::filter);
};
}
public static class Config {
//live it empty because we dont need any particular configuration
}
}
2. I've added AuthFilter as filter to each service in application.properties:
api-gateway/src/resource/application.properties
##Workshop service routes
spring.cloud.gateway.routes[0].id=workshop-service
spring.cloud.gateway.routes[0].uri=lb://workshop-service
spring.cloud.gateway.routes[0].predicates[0]=Path=/api/v1/workshop/**
spring.cloud.gateway.routes[0].filters[0]=AuthFilter
##Manage service routes
spring.cloud.gateway.routes[1].id=manager-service
spring.cloud.gateway.routes[1].uri=lb://manager-service
spring.cloud.gateway.routes[1].predicates[0]=Path=/api/v1/manage/**
spring.cloud.gateway.routes[1].filters[0]=AuthFilter
##Manage service for singIn. Here we dont need to add AuthFilter, cause sign in page should be available for all
spring.cloud.gateway.routes[2].id=manager-service-sign-in
spring.cloud.gateway.routes[2].uri=lb://manager-service
spring.cloud.gateway.routes[2].predicates[0]=Path=/api/v1/auth/signIn
...
3. Manager-service microservice used to control base entities for system, such as users, roles, organizations where users working are and so on, so here I added SecurityConfig and WebConfig, because this microservice will be responsible for JWT generating:
manager-service/src/main/java/.../SecurityConfig.java
#EnableWebSecurity
public class SecurityConfig {
#Bean
public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.csrf().disable()
.authorizeRequests().anyRequest().permitAll();
return httpSecurity.build();
}
}
manager-service/src/main/java/.../WebConfig.java
#EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
private static final Long MAX_AGE=3600L;
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedHeaders(
HttpHeaders.AUTHORIZATION,
HttpHeaders.CONTENT_TYPE,
HttpHeaders.ACCEPT)
.allowedMethods(
HttpMethod.GET.name(),
HttpMethod.POST.name(),
HttpMethod.PUT.name(),
HttpMethod.DELETE.name())
.maxAge(MAX_AGE)
.allowedOrigins("http://localhost:8100")
.allowCredentials(false);
}
}
4. In controller, that represents auth I also added #CrossOrigin annotation to class:
manager-service/src/main/java/.../AuthController.java
#RestController
#RequestMapping("api/v1/auth")
#CrossOrigin(origins = "http://localhost:8100")
#Slf4j
public class AuthController {
private final AuthService authService;
#Autowired
public AuthController(AuthService authService) {
this.authService = authService;
}
#PostMapping("/signIn")
public ResponseEntity<EmployeeDTO> signIn(#RequestBody CredentialsDTO credentialsDTO) {
log.info("Trying to login {}", credentialsDTO.getLogin());
return ResponseEntity.ok(EmployeeMapper.convertToDTO(authService.signIn(credentialsDTO)));
}
#PostMapping("/validateToken")
public ResponseEntity<EmployeeDTO> validateToken(#RequestParam String token) {
log.info("Trying to validate token {}", token);
Employee validatedTokenUser = authService.validateToken(token);
return ResponseEntity.ok(EmployeeMapper.convertToDTO(validatedTokenUser));
}
}
5. For frontend I use Vue.js. For requests I use axios. Here are post-request to login:
axios.post('http://localhost:8080/api/v1/auth/signIn', this.credentials).then(response => {
console.log('response = ', response)
console.log('token from response', response.data.token)
this.$store.commit('saveToken', response.data.token)
}).catch(error => {
console.log('Error is below')
console.log(error)
})
All what I'm getting is an error: Access to XMLHttpRequest at 'http://localhost:8080/api/v1/auth/signIn' from origin 'http://localhost:8100' 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.. Below you'll see headers, that displays Chrome with request:
I've been trying to add another one corsConfiguration, tried to mark with CrossOrigin annotation only method, not class at all but it hadn't take any effects. If I try to make such requests with postman it gives me expected response with generated token.
I'll be grateful for any idea what could I do wrong.
Thanks!
UPDATE: As I understood well - all problems is in api-gateway. If I make requests directly to service - I get right response, but if I make request through gateway - I'm facing an error, logs of api-gateway below:
2022-07-05 00:34:18.128 TRACE 8105 --- [or-http-epoll-5] o.s.c.g.h.p.PathRoutePredicateFactory : Pattern "[/api/v1/workshop/**]" does not match against value "/api/v1/auth/signIn"
2022-07-05 00:34:18.129 TRACE 8105 --- [or-http-epoll-5] o.s.c.g.h.p.PathRoutePredicateFactory : Pattern "[/api/v1/manage/**]" does not match against value "/api/v1/auth/signIn"
2022-07-05 00:34:18.129 TRACE 8105 --- [or-http-epoll-5] o.s.c.g.h.p.PathRoutePredicateFactory : Pattern "/api/v1/auth/signIn" matches against value "/api/v1/auth/signIn"
2022-07-05 00:34:18.129 DEBUG 8105 --- [or-http-epoll-5] o.s.c.g.h.RoutePredicateHandlerMapping : Route matched: manager-service-sign-in
2022-07-05 00:34:18.129 DEBUG 8105 --- [or-http-epoll-5] o.s.c.g.h.RoutePredicateHandlerMapping : Mapping [Exchange: OPTIONS http://localhost:8080/api/v1/auth/signIn] to Route{id='manager-service-sign-in', uri=lb://manager-service, order=0, predicate=Paths: [/api/v1/auth/signIn], match trailing slash: true, gatewayFilters=[], metadata={}}
2022-07-05 00:34:18.129 DEBUG 8105 --- [or-http-epoll-5] o.s.c.g.h.RoutePredicateHandlerMapping : [e5b87280-8] Mapped to org.springframework.cloud.gateway.handler.FilteringWebHandler#78df1cfc
After research I've solved problem. It was all Gateway's fault
As I mentioned before, direct request gives me right response, but only if I go through api-gateway it gives me an errors.
So solution is to add CORS Configuration rules to gateway:
spring:
cloud:
gateway:
default-filters:
- DedupeResponseHeader=Access-Control-Allow-Origin Access-Control-Allow-Credentials, RETAIN_UNIQUE
globalcors:
corsConfigurations:
'[/**]':
allowedOrigins: "http://localhost:8100"
allowedHeaders: "*"
allowedMethods: "*"
Please, note that if you don't add section with gateway: default-filters you will be facing similar error with header that contains multiple values.
Thanks to answer by Pablo Aragonés in another question and Spring Cloud Documentation
add this to applications.yml in your gateway, solved issue for me:
spring:
cloud:
gateway:
default-filters:
- DedupeResponseHeader=Access-Control-Allow-Origin Access-Control-
Allow-Credentials, RETAIN_UNIQUE
globalcors:
corsConfigurations:
'[/**]':
allowedOrigins: "http://localhost:<your port>"
allowedHeaders: "*"
allowedMethods: "*"
I have faced similar issue & got resolved by defining following bean in my Configuration.
#Bean
public CorsFilter corsFilter() {
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
final CorsConfiguration config = new CorsConfiguration();
config.setAllowedOrigins(Collections.singletonList("http://localhost:8100")); // Provide list of origins if you want multiple origins
config.setAllowedHeaders(Arrays.asList("Origin", "Content-Type", "Accept"));
config.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "OPTIONS", "DELETE", "PATCH"));
config.setAllowCredentials(true);
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
You can comment out all other details e.g. #CrossOrigin(origins = "http://localhost:8100"), WebConfig.java, SecurityConfig.java as once we define above bean these things are not required.
Your code may not be running because you have defined bean , security config as well as webconfig which might be conflicting while processing your request.

RestController receiving incorrect charset in RequestBody

I have following api:
#ApiOperation(value = "Search product by text")
#PostMapping("/get/search")
public ResponseEntity<List<ShopProductDTO>> get(#RequestBody SearchProductRequestDTO search) {
//searching product here using search.getSearchText() value
}
Via postman I am sending:
{"searchText":"Утюг"}
But what I am receiving/seeing in logs:
SearchProductRequestDTO{searchText='РЈС‚СРі'}
After enabling DEBUG I see Http11InputBuffer logs where body:
{"searchText":"ГђВЈГ‘<U+0082>Г‘<U+008E>ГђВі"}
What I have done (none of them helped):
Added following properties in application.properties
spring.http.encoding.charset=UTF-8
spring.http.encoding.enabled=true
spring.http.encoding.force=true
spring.messages.basename=messages
spring.messages.encoding=UTF-8
Exposed CharacterEncodingFilter
#Bean
#Order(Ordered.HIGHEST_PRECEDENCE)
public CharacterEncodingFilter charsetFilter() {
CharacterEncodingFilter filter = new CharacterEncodingFilter();
filter.setEncoding("UTF-8");
filter.setForceEncoding(true);
return filter;
}
Executed jar file with -Dfile.encoding=UTF-8 param
Included following headers in Postman
accept-charset:utf-8
content-type:application/json;charset=utf-8
What else I should do? Or am I missing something?
Try to change your code to this:
#ApiOperation(value = "Search product by text")
#PostMapping(value="/get/search", consumes="application/json;charset=UTF-8")
public ResponseEntity<List<ShopProductDTO>> get(#RequestBody SearchProductRequestDTO search) {
//searching product here using search.getSearchText() value
}
The change is in your line
#PostMapping(value="/get/search", consumes="application/json;charset=UTF-8")
If the issue is logging, change logger encoding to support UTF-8
#encoding- Over-ride the default character-encoding scheme.
logging.console.encoding=UTF-8

CORS error occurs when establishing a restAPI in springboot

trying to connect my RestAPI(SpringBoot) to angular but there's this cors error which does not allow the connection to happen.
the error in the front end side is
"Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:8080/hello-world-bean/path-var/root. (Reason: CORS preflight channel did not succeed)."
And one more thing i am using the SpringBootSecurity Service by adding a username and password in application.properties file.
I tried to use Filter, WebMvcConfigurer, WebSecurityConfigurerAdapter but i am not in luck.
executeHelloWorldBean(){
return this.http.get<HelloWorldBeans>("http://localhost:8080/hello-world-bean/");
}
executeHelloWorldBeanWithParameter(name){
let basicAuthString = this.createBasicAuthenticationHeader();
let headers = new HttpHeaders({
Authorizaton : basicAuthString
})
return this.http.get<HelloWorldBeans>(`http://localhost:8080/hello-world-bean/path-var/${name}`,
{headers})
}
createBasicAuthenticationHeader(){
let username='root'
let password ='password'
let basicAuthString = 'Basic ' + window.btoa(username + ':' + password)
return basicAuthString}}
#Configuration
public class SpringSecurityBasicAuth implements WebMvcConfigurer {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins(
"http://localhost:4200")
.allowedMethods("GET", "POST", "PUT", "DELETE", "HEAD")
.allowCredentials(true)
;
}
}
I just want my RestApi to be connected to my FrontEnd

Categories

Resources