I use <spring.version>4.2.0.RELEASE</spring.version>, <spring.security.version>4.0.2.RELEASE</spring.security.version>, and <spring.security.oauth2.version>2.0.9.RELEASE</spring.security.oauth2.version>.
I use #CrossOrigin to dela with CORS. For now, I want to allow all the headers and all the methods. I can use any of the other headers than Authorization without any CORS issue. But with Authorization(header to send Bearer token), I get CORS issue. I use #CrossOrigin annotatiion at Class level and allow all the headers as below -
#CrossOrigin(allowedHeaders = {"*"})
No 'Access-Control-Allow-Origin' header is present on the requested
resource
How can I allow Authorization header as well as I did all other headers and avoid CORS issues?
You can add the following to any configuration file:
#Bean
public CorsFilter corsFilter() {
final UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource();
final CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.setAllowCredentials(true);
corsConfiguration.addAllowedOrigin("*");
corsConfiguration.addAllowedHeader("*");
corsConfiguration.addAllowedMethod("*");
urlBasedCorsConfigurationSource.registerCorsConfiguration("/**", corsConfiguration);
return new CorsFilter(urlBasedCorsConfigurationSource);
}
EDIT
For XML configuration, you could create a custom filter and add it to your filter chain:
public class CorsFilter implements Filter {
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", "*");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "*");
chain.doFilter(req, res);
}
public void init(FilterConfig filterConfig) {}
public void destroy() {}
}
XML config
<security:filter-chain-map>
<sec:filter-chain pattern="/**"
filters="
ConcurrentSessionFilterAdmin,
securityContextPersistenceFilter,
logoutFilterAdmin,
usernamePasswordAuthenticationFilterAdmin,
basicAuthenticationFilterAdmin,
requestCacheAwareFilter,
securityContextHolderAwareRequestFilter,
anonymousAuthenticationFilter,
sessionManagementFilterAdmin,
exceptionTranslationFilter,
filterSecurityInterceptorAdmin,
CorsFilter"/>
</security:filter-chain-map>
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 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!
I have implemented Filter for CORS in spring boot.The code is as follow:-
#SpringBootApplication
#Component
public class Application implements Filter {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Override
public void init(FilterConfig filterConfig) throws ServletException {
}
#Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
response.setHeader("Access-Control-Allow-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");
filterChain.doFilter(servletRequest, servletResponse);
}
#Override
public void destroy() {
}
}
To get the access_token from oauth2 I have created following object from angularjs:-
{"url":"http://localhost:8080/oauth/token?grant_type=client_credentials&client_id=clientId&client_secret=clientSecret","headers":{"Authorization":"Basic token_value"},"withCredentials":true,"method":"POST"}
I am getting following error when I hit the server:-
OPTIONS url... 401() Response for preflight has invalid HTTP status code 401
I have looked for the solutions for similar problems in stack overflow but none of them fixed my problem.Could someone please help on this?
Following piece of code solved my problem
#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(Ordered.HIGHEST_PRECEDENCE);
return bean;
}
The code sample is taken from https://github.com/spring-projects/spring-security-oauth/issues/938
Please read more about Preflight requests.
They simply suggest the browser if the server supports a cross-origin request. The response to such OPTIONS requests should good (i.e. < 400).
I think the statement filterChain.doFilter(servletRequest, servletResponse); is passing the request further, instead of returning a response.
You can read more about enabling CORS using Spring in Java here Enable CORS for OPTIONS request using Spring Framework
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!