I'm using spring-web for building a json/rest backend for my web/mobile application.
I was using javax.servlet.Filter, adding appropriate cors header:
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, PUT");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "x-requested-with, accept, authorization, content-type");
response.setHeader("X-Frame-Options", "SAMEORIGIN");
chain.doFilter(req, res);
}
Now i'm trying to upgrade to spring 4.2.5 and use #CrossOrigin annotation, but it seems that OPTION dispatched response doesn't contains appropriate headers.
Here my configuration:
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = "it.foo.api.rest", useDefaultFilters = false,
includeFilters = #ComponentScan.Filter(value = Controller.class, type = FilterType.ANNOTATION))
public class WebConfig extends WebMvcConfigurerAdapter {
...
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**");
// .allowCredentials(true)
// .allowedOrigins("*")
// .maxAge(3600)
// .allowedMethods("PUT", "POST", "GET", "OPTIONS", "DELETE")
// .allowedHeaders("content-type", "authorization", "x-requested-with", "accept", "origin", "Access-Control-Request-Method", "Access-Control-Request-Headers")
// .exposedHeaders("Access-Control-Allow-Origin", "Access-Control-Allow-Credentials");
// .exposedHeaders("x-requested-with, accept, authorization, content-type");
}
as you can see i've tryed some configurations.
My controller:
#CrossOrigin(allowCredentials="true",
methods={RequestMethod.GET,RequestMethod.POST,RequestMethod.PUT,RequestMethod.OPTIONS,RequestMethod.DELETE},
allowedHeaders={"x-requested-with", "accept", "authorization", "content-type"},
exposedHeaders={"access-control-allow-headers", "access-control-allow-methods", "access-control-allow-origin", "access-control-max-age", "X-Frame-Options"})
#RestController
#RequestMapping(value="/admin")
public class AdminUserController extends BaseController {
#RequestMapping(value = "/login", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
public HttpEntity<AdminUserResource> postLogin(#RequestBody AdminLoginCredentials credentials) {
return new ResponseEntity<AdminUserResource>(..., HttpStatus.OK);
}
Again i've tested with several configuration, with only basic #CrossOrigin annotation.
Headers WITH servlet filter (old version):
Headers WITHOUT filter and WITH #CrossOrigin (new version, not working):
i can't find out what i'm missing!
Related
I'm using SpringBoot 2.5.6.
I tryto upload file via byte array in the FileController class:
#PostMapping("/uploadFileViaStream")
public JSONObject uploadFile1(#RequestBody byte[] bytes) {
ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes);
String fileName = genUUID();
String fileId = null;
fileId = fileService.uploadFile("", fileName, inputStream);
Map<String, Object> map = new HashMap<>(1);
map.put("file", fileId);
return ZheliResult.ok(map);
}
And add #CrossOrigin(origins="*") on the FileController class.
The Chrome says No 'Access-Control-Allow-Origin' header is present on the requested resource. which is a CORS issue.
Then I delete #CrossOrigin(origins="*"), and add a configuration class:
#Configuration
public class MvcConfiguration implements WebMvcConfigurer {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/*")
.allowedOriginPatterns("*")
.allowCredentials(true)
.allowedMethods("GET", "POST", "DELETE", "PUT","PATCH", "HEAD", "OPTIONS")
.maxAge(3600);
}
}
Still doesn't work.
Then I delete this and turn to Nginx to configure CORS:
add_header Access-Control-Allow-Origin $http_origin;
add_header Access-Control-Allow-Credentials true;
add_header Access-Control-Allow-Methods *;
add_header Access-Control-Allow-Headers *;
It does work but after a while the CORS problem appeared again.
Then I configure the SpringCloud Gateway in the bootstrap.yml:
gateway:
globalcors:
add-to-simple-url-handler-mapping: true
cors-configurations:
'[/**]':
allowedOrigins: "*"
allowedHeaders: "*"
allowedMethods: "*"
allowCredentials: true
The Chrome says:
The 'Access-Control-Allow-Origin' header contains multiple values '*, *', but only one is allowed.
If I change * int the Nginx or Gateway to http://172.20.10.9:8080, The Chrome says:
The 'Access-Control-Allow-Origin' header contains multiple values 'http://172.20.10.9:8080, http://172.20.10.9:8080', but only one is allowed.
So can anyone help me?
I would simply add filter requests and allow CORS to pass. The HIGHEST_PRECEDENCE order is importand. Do not neave it out!
#Component
#Order(Ordered.HIGHEST_PRECEDENCE)
public class CorsFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
HttpServletRequest request = (HttpServletRequest) req;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Methods",
"DELETE, GET, OPTIONS, POST, PUT");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers",
"Origin, X-Requested-With, Content-Type, Accept, Key, Authorization");
if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
response.setStatus(HttpServletResponse.SC_OK);
} else {
chain.doFilter(req, res);
}
}
}
I'm having trouble trying to send a custom header param from my frontend to the controller.
I've set the endpoint to get the header param:
public ResponseEntity<DashboardBean> atualizarDadosDashboard(#RequestHeader(name = "idEmpresa") Long idEmpresa){
But when I try to consume this endpoint, I get failed response and the application doesn't log any error.
Here I have the browser console showing the failed request:
The second dashboard request is a OPTIONS type. The first is the GET request.
Here you can see the failed request headers with the custom header "idEmpresa":
I'm using Angular on the frontend. As you can see below, I'm adding the header to the request:
....
protected httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/json',
'Authorization': this.token,
'idEmpresa': String(this.idEmpresa)
})
};
atualizarDashboard(): Observable<DashboardModel> {
return this.httpClient.get<DashboardModel>(this.baseUrl, this.httpOptions);
}
....
On my spring boot application there is nothing on the logs about this request!!
Problem solved.
I have a CORS Filter in my application. I had to add my custom header param to the
Access-Control-Allow-Headers
list to allow it. After that, the endpoint was consumed and worked as expected.
This is how my Filter is now:
#Component
#Order(Ordered.HIGHEST_PRECEDENCE)
public class SimpleCORSFilter implements Filter {
private final Log logger = LogFactory.getLog(this.getClass());
#Override
public void init(FilterConfig fc) throws ServletException {
logger.info("SimpleCORSFilter loaded");
}
#Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) resp;
HttpServletRequest request = (HttpServletRequest) req;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, PUT");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers",
"x-requested-with, authorization, Content-Type, " +
"Authorization, credential, X-XSRF-TOKEN, idEmpresa");
if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
response.setStatus(HttpServletResponse.SC_OK);
} else {
chain.doFilter(req, resp);
}
}
#Override
public void destroy() {
}
}
I want to accept origin as http://192.168.1.35:4200 and I created the CORSFilter like this in the springboot:
#Component
#Order(Ordered.HIGHEST_PRECEDENCE)
public class CORSFilter implements Filter {
public CORSFilter() {
}
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
HttpServletRequest request = (HttpServletRequest) req;
response.setHeader("Access-Control-Allow-Origin", "http://192.168.1.35:4200");
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS, PATCH, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "X-Requested-With, Authorization, X-Auth-Token, Origin, Content-Type, Accept, Auth_Token");
if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
response.setStatus(HttpServletResponse.SC_OK);
} else {
chain.doFilter(req, res);
}
}
#Override
public void init(FilterConfig filterConfig) {
}
#Override
public void destroy() {
}
}
And I created the request like this to call the spring rest api from angular:
getAllUsers(): void {
this.accessToken = JSON.parse(window.sessionStorage.getItem('token')).access_token;
this.httpClient.get<User[]>(`${BASE_URL}/fam-users/user?access_token=${this.accessToken}`, httpOptions).subscribe(data => {
this.dataChange.next(data);
},
(err: ApiError) => {
this.snackBar.openSnackBar(err.error.message, 'close', 'red-snackbar');
});
}
When I send request, It says that
Access to XMLHttpRequest at 'http://192.168.1.35:8080/fam-users/user?access_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NTAwNDMwODMsInVzZXJfbmFtZSI6ImFkbWluIiwiYXV0aG9yaXRpZXMiOlsiRkFfQU1FTkQiLCJGQV9ORVciXSwianRpIjoiOWViMzZjNzAtOGUwOS00YzViLWI0OWQtNDNmZTRhOTkzNDgzIiwiY2xpZW50X2lkIjoiY2xpZW50Iiwic2NvcGUiOlsicmVhZCIsIndyaXRlIiwidHJ1c3QiXX0.IETZOJE8tIqNc249HmTcJHuZpZFY1TP4PLcbqUOF3qc' from origin 'http://192.168.1.35:4200' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
But all other requests from 'http://192.168.1.35:4200' are working fine.
Can Someone guide me to solve this issue?
There is a #CrossOrigin annotation in spring boo, for example:
#CrossOrigin(origins = "http://localhost:9000")
#GetMapping("/greeting")
public Greeting greeting(#RequestParam(required=false, defaultValue="World") String name) {
System.out.println("==== in greeting ====");
return new Greeting(counter.incrementAndGet(), String.format(template, name));
}
for more please have a look
I know there are lots of posts regarding the same problem, but none of it resolve my issue.
I have a springboot microservice application with the following API
#RestController
#RequestMapping({ "/sample" })
public class SampleController {
#CrossOrigin(origins = "http://192.168.0.31:8080", allowCredentials = "false", allowedHeaders = "*")
//#CrossOrigin//(allowCredentials = "false")
#RequestMapping(value="/welcome" , method=RequestMethod.POST, produces={"application/json"})
public JSONObject getWelcomeResponse(#RequestParam Map<String,String> request){
JSONObject response=new JSONObject();
response.put("response", "Welcome user");
System.out.println("Complterd ****");
return response;
}
}
properties file
server.port=8081
security.user.name=test
security.user.password=test123
#security.basic.enabled=false
And my client code is
$(document).ready(function(){
$.ajax({
url: "http://192.168.0.31:8081/sample/welcome",
type : "POST",
crossDomain:true,
crossOrigin:true,
beforeSend: function (xhr) {
// Use BASIC Authentication
xhr.setRequestHeader ("Authorization", "Basic " + btoa("test:test123"));
},
error: function(xhr, status, errorThrown) {
alert(status, errorThrown);
// Error block
console.log("xhr: " + xhr);
console.log("status: " + status);
console.log("errorThrown: " + errorThrown);
}
})
.then(function(data, status, xhr) {
alert(data);
console.log("xhr: " + xhr);
console.log("status: " + status);
console.log("data: "+ data);
$('.message').append(JSON.stringify(data));
});
});
When I disable the basic auth, The cors request is works fine. But if it enabled it gives 401 preflight request error.
I have tried #CrossOrigin with default as well as customized way also. But getting the same error. Also tried with a filter class like below.
#EnableWebMvc
public class MyAppConfigurations implements Filter {
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletResponse httpResponse = (HttpServletResponse) response;
HttpServletRequest httpRequest = (HttpServletRequest) request;
if("OPTIONS".equalsIgnoreCase(httpRequest.getMethod())) {
httpResponse.setStatus(HttpServletResponse.SC_OK);
System.out.println("filterde response");
} else {
chain.doFilter(request, response);
}
}
}
Can somebody help me to figure out, what I am missing on this code.
You have to create CORS FILTER for your Spring MicroService
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
#Component
#Order(Ordered.HIGHEST_PRECEDENCE)
public class CorsFilter implements Filter {
#Override
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain filterChain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
HttpServletRequest request = (HttpServletRequest) req;
if (response instanceof HttpServletResponse) {
addCorsHeader(response);
if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
response.setStatus(HttpServletResponse.SC_OK);
} else {
filterChain.doFilter(req, res);
}
}
}
private void addCorsHeader(HttpServletResponse response) {
response.addHeader("Access-Control-Allow-Origin", "http://localhost:4200"); // Update with yours
response.addHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE, HEAD");
response.addHeader("Access-Control-Allow-Credentials", "true");
response.addHeader("Access-Control-Allow-Headers", "Authorization, X-PINGOTHER, Origin, X-Requested-With, Content-Type, Accept");
response.addHeader("Access-Control-Max-Age", "1728000");
}
#Override
public void destroy() {
}
#Override
public void init(FilterConfig filterConfig) throws ServletException {
}
}
Add #CrossOrigin before class like
#RequestMapping({ "/sample" })
#CrossOrigin(origins = "http://192.168.0.31:8080")
public class SampleController {
try adding in your /welcome Rest Controller
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "x-requested-with");
According to the CORS specification, the CORS preflight request must be accepted without any authentication.
You have to configure your web server or Spring Security to disable authentication on all OPTIONS requests related to preflight.
I am a backend developer and i am providing a spring boot rest API with JWT security to consume for a front end developer who calls the api from local host.So when he calls a POST request he says he gets an CORS error.So I added the part
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "Content-Type, Accept, X-Requested-With, remember-me");
chain.doFilter(request, response);
}
But still he gets the error.What may be the cause.Any help is appreciated
OPTIONS https:my.domain/url 401 (Unauthorized)
when it is a POST request.
Controller code:
#RestController
public class RegistrationController {
#Autowired
#Qualifier("restTemplateUserRegitration")
private RestTemplate restTemplateUserRegitration;
#RequestMapping(value="${user.endpoint}",produces={MediaType.APPLICATION_JSON_VALUE},method=RequestMethod.POST)
public ResponseEntity<?> registerUser(#RequestBody Model ModelRequest){
Map<String, Object> Status=new HashMap<String, Object>();
FeedBackStatus = restTemplateUserRegitration.postForObject("http:serviceurl",registration/single",Model.class,Map.class );
return ResponseEntity.ok(Status);
}
}
I also had a similar experience. We have solved the problem as follows.
This code added in securityConfiguration.
The browser will send the OPTIONS request first before sending the POST request. Therefore, when the request is sent, the authorization header value is not included in the request header, so the JWT filter judges that the user is unauthenticated.
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring()
.antMatchers(HttpMethod.OPTIONS);
}
Try this first, this should allow all origins, but it is security risk.
response.setHeader("Access-Control-Allow-Origin", "*");
This is one option. Not sure if its an elegant one
#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 CorsFilter(source));
bean.setOrder(0);
return bean;
}
Put this in any spring bean.
You can create your own CorsConfiguration
#EnableWebSecurity
class SecurityConfig extends WebSecurityConfigurerAdapter {
CorsConfigurationSource corsConfigurationSource = new CorsConfigurationSource() {
#Override
public CorsConfiguration getCorsConfiguration(HttpServletRequest request) {
CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.addAllowedOrigin("http://localhost:63342");
corsConfiguration.addAllowedHeader("Authorization");
corsConfiguration.setAllowedMethods(Arrays.asList("POST", "GET"));
corsConfiguration.setMaxAge(3600L);
return corsConfiguration;
}
};
And add it to configuration.
.and().cors().configurationSource(corsConfigurationSource);
And try using this annotation
#CrossOrigin
You should implement a filter like this:
public class CORSFilter extends OncePerRequestFilter {
private final Logger LOG = LoggerFactory.getLogger(CORSFilter.class);
#Override
protected void doFilterInternal(HttpServletRequest req, HttpServletResponse res, FilterChain chain) throws ServletException, IOException {
LOG.info("Adding CORS Headers ........................");
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
res.setHeader("Access-Control-Max-Age", "3600");
res.setHeader("Access-Control-Allow-Headers", "X-PINGOTHER,Content-Type,X-Requested-With,accept,Origin,Access-Control-Request-Method,Access-Control-Request-Headers,Authorization");
res.addHeader("Access-Control-Expose-Headers", "xsrf-token");
if ("OPTIONS".equals(req.getMethod())) {
res.setStatus(HttpServletResponse.SC_OK);
} else {
chain.doFilter(req, res);
}
}
}
Found this from the post Cross Origin Request Blocked Spring MVC Restful Angularjs
Hope this help!