I serve my front- and backend from two different servers. Now I am trying to get CORS working on the Spring-Boot-Jersey backend. I tried everything I could find on the internet but nothing seem to work or I am missing something.
My current setup uses a ContainerResponseFilter. I tried registering it automatically with #Provider and manually in the Jersey configuration.
ContainerResponseFilter
#Provider
public class CORSFilter implements ContainerResponseFilter {
#Override
public void filter(ContainerRequestContext request,
ContainerResponseContext response) throws IOException {
response.getHeaders().add("Access-Control-Allow-Origin", "*");
response.getHeaders().add("Access-Control-Allow-Headers",
"origin, content-type, accept, authorization");
response.getHeaders().add("Access-Control-Allow-Credentials", "true");
response.getHeaders().add("Access-Control-Allow-Methods",
"GET, POST, PUT, DELETE, OPTIONS, HEAD");
}
}
Maybe it is important but I also used Spring-Security-oauth2 by adding the #EnableOAuth2Sso annotation. Please tell me if you need more of my setup.
I fixed it this way,
First create a class
public class CORSResponseFilter implements ContainerResponseFilter {
public void filter(ContainerRequestContext requestContext,ContainerResponseContext responseContext)
throws IOException {
MultivaluedMap<String, Object> headers = responseContext.getHeaders();
headers.add("Access-Control-Allow-Origin", "*");
//headers.add("Access-Control-Allow-Origin", "http://abcd.org"); //allows CORS requests only coming from abcd.org
headers.add("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT");
headers.add("Access-Control-Allow-Headers", "X-Requested-With, Content-Type, X-Codingpedia");
}
}
The filter must inherit from the ContainerResponseFilter interface and must be registered as a provider:
public class JerseyConfig extends ResourceConfig {
public JerseyConfig() {
register(CORSResponseFilter.class);
//other registrations
}
}
Fixed it by using the CORSFilter displayed in https://spring.io/blog/2015/01/20/the-resource-server-angular-js-and-spring-security-part-iii
#Component
#Order(Ordered.HIGHEST_PRECEDENCE)
class CorsFilter implements Filter {
void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) {
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, PUT, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Allow-Headers", "x-requested-with");
response.setHeader("Access-Control-Max-Age", "3600");
if (request.getMethod()!='OPTIONS') {
chain.doFilter(req, res);
} else {
}
}
void init(FilterConfig filterConfig) {}
void destroy() {}
}
Not sure if the #Provider annotation is supported by Spring. Try replacing the #Provider annotation with Springs #Component and the CORSFilter should extend org.springframework.web.filter.OncePerRequestFilter. This is the Spring way of configuring Filters and this will work for any application server.
You can also configure CORS via the WebMvcConfigurerAdapter, which might be more compact:
#Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurerAdapter() {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedHeaders("...") // add headers
.allowedMethods(".."); // add methods
}
};
}
Check out this guide!
Related
Details:
I am using spring boot oauth2 resource server which is giving me CORS even after trying different approaches to filter this off.
How do my code look ?
Its a simple resource server with spring boot with spring-cloud-starter-oauth2 and spring-cloud-starter-security as two major dependencies.
I have used java annotations to make this a resource server :
#CrossOrigin(origins = "*", maxAge = 3600, allowedHeaders = "*")
#RestController
#RequestMapping("/api/v1")
#EnableResourceServer
Here is how I tried to resolve this :
I tried to add a custom filter which skips further filter calls with code below. After this I got "Authorization Header not allowed in preflight request on browser". After adding CORS everyehere extension to my browser my requests succeeded.
#EnableWebSecurity(debug = true)
#Order(Ordered.HIGHEST_PRECEDENCE)
public class WebSecurityConfig implements Filter {
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT, OPTIONS, DELETE, PATCH");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
response.setHeader("Access-Control-Expose-Headers", "Location");
System.out.println(request.getMethod());
System.out.println("-----------------");
if(!request.getMethod().equals("OPTIONS")) {
chain.doFilter(req, res);
}
}
#Override
public void init(FilterConfig filterConfig) {}
#Override
public void destroy() {}
}
I had the same problem and
that was the resolution.
public class ResourceServerCustom extends ResourceServerConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
http.csrf().disable().cors().disable().authorizeRequests().antMatchers("/oauth/token/**").permitAll()
.anyRequest().authenticated().and().exceptionHandling()
.authenticationEntryPoint(new AuthExceptionEntryPoint());
http.cors().configurationSource(request -> new CorsConfiguration().applyPermitDefaultValues());
}
}
And others configs.
public class WebSecurityCustom extends WebSecurityConfigurerAdapter {
public TokenStore tokenStore;
#Bean
#Override
protected AuthenticationManager authenticationManager() throws Exception {
return super.authenticationManager();
}
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/v2/api-docs", "/configuration/ui", "/swagger-resources/**",
"/configuration/security", "/swagger-ui.html", "/webjars/**");
web.ignoring().antMatchers(HttpMethod.OPTIONS);
}
}
public class CorsFilterCustom extends OncePerRequestFilter {
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws ServletException, IOException {
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Methods",
"ACL, CANCELUPLOAD, CHECKIN, CHECKOUT, COPY, DELETE, GET, HEAD, LOCK, MKCALENDAR, MKCOL, MOVE, OPTIONS, POST, PROPFIND, PROPPATCH, PUT, REPORT, SEARCH, UNCHECKOUT, UNLOCK, UPDATE, VERSION-CONTROL");
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(request, response);
}
}
}
public class AuthorizationServerCustom implements AuthorizationServerConfigurer {
#Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security.checkTokenAccess("isAuthenticated()");
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.tokenStore(tokenStore()).authenticationManager(authenticationManager);
}
}
public class AuthExceptionEntryPoint implements AuthenticationEntryPoint {
#Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException arg2)
throws ServletException, IOException {
final Map<String, Object> mapBodyException = new HashMap<>();
mapBodyException.put("error", "Error from AuthenticationEntryPoint");
mapBodyException.put("message", "Message from AuthenticationEntryPoint");
mapBodyException.put("exception", "My stack trace exception");
mapBodyException.put("path", request.getServletPath());
mapBodyException.put("timestamp", (new Date()).getTime());
response.setContentType("application/json");
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
final ObjectMapper mapper = new ObjectMapper();
mapper.writeValue(response.getOutputStream(), mapBodyException);
}
}
You could configure cors by adding a configuration class with different variations like this
#Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
CorsConfiguration config = new CorsConfiguration();
config.setAllowedMethods(Collections.singletonList("*"));
http.cors().configurationSource(request -> config);
}
}
or just disable like this
#Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().disable();
}
}
I'm trying to request data from my backend through my frontend, but I'm getting the error:
Access to XMLHttpRequest at 'http://localhost:8081/api/transactions/' from origin 'http://localhost:4200' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
I am able to get the data with postman, but not my frontend. I'm using angular and spring boot.
My application.java:
#EnableJpaRepositories
#EntityScan
#SpringBootApplication
public class KoalaTreeAccountingApplication {
public static void main(String[] args) {
SpringApplication.run(KoalaTreeAccountingApplication.class, args);
}
}
My security config:
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest()
.permitAll()
.and().csrf().disable();
}
}
My service to make the http call in angular:
#Injectable({
providedIn: 'root'
})
export class TransactionService {
baseUrl = 'http://localhost:8081/api/';
transactionUrl = this.baseUrl + 'transactions/';
constructor(private http: HttpClient, private logger : Logger){ }
getAllTransactions() : Observable<Transaction[]> {
this.logger.log("Request all transactions");
return this.http.get<Transaction[]>(this.transactionUrl);
}
getTransactionById(id : number) : Observable<Transaction> {
this.logger.log("Request transaction " + id);
return this.http.get<Transaction>(this.transactionUrl + id);
}
}
Edit: I've tried
https://spring.io/guides/gs/rest-service-cors/
Spring Security CORS filter not working
Security configuration with Spring-boot
https://stackoverflow.com/a/31748398/12025088
Protip: clean install before re-running the application after a change. I'm an idiot.
Fixed by using this instead of SecurityConfig.java:
#Component
public class SimpleCORSFilter 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", "POST, GET, OPTIONS, DELETE, PUT");
response.setHeader("Access-Control-Max-Age", "36000");
response.setHeader("Access-Control-Allow-Headers", "origin, content-type, accept");
chain.doFilter(req, res);
}
public void init(FilterConfig filterConfig) {
}
public void destroy() {
}
}
You need to configure CORS on the methods of your RestController that you want to allow it. CORS is a server response.
#CrossOrigin(origins = "http://localhost:4200")
#GetMapping("/")
public List<Transaction> findAllTransactions() {
return transactionService.findAllTransactions(); }
}
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
This question already has answers here:
No 'Access-Control-Allow-Origin' header is present on the requested resource—when trying to get data from a REST API
(26 answers)
Closed 4 years ago.
I have red tons of example how to configure CORS in Java Spring, but it is still not working in project with websockets request.
It works with mcv api paths, but my websockets path's returns error:
Failed to load http://localhost:8080/chat/info?t=1537264329515: No
'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'http://localhost:3000' is therefore not allowed
access. The response had HTTP status code 403.
My WebMvcConfig:
#Configuration
public class WebMvcConfig implements WebMvcConfigurer
{
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedOrigins("http://localhost:3000");
}
}
Maybe someone had same error or have any solutions how should I solve this error?
If someone will have this question, I solved my problem in WebsocketConfig like this:
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/chat").setAllowedOrigins("http://localhost:3000").withSockJS();
}
Try this, it worked for me when I had the same problem, possibly not the best practice though:
#Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowCredentials(true)
.allowedHeaders("*")
.allowedMethods("OPTIONS", "GET", "POST", "PUT", "DELETE", "PATCH")
.allowedOrigins("*");
}
...
}
add another filter
public class CorsFilter extends OncePerRequestFilter {
static final String ORIGIN = "Origin";
protected void doFilterInternal(
HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
String origin = request.getHeader(ORIGIN);
response.setHeader("Access-Control-Allow-Origin", "http://localhost:4200");
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Methods", "PUT, POST, GET, OPTIONS, DELETE, PATCH");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "content-type, authorization");
if (request.getMethod().equals("OPTIONS"))
response.setStatus(HttpServletResponse.SC_OK);
else
filterChain.doFilter(request, response);
}
}
and added to the series of my filters:
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
...
#Bean
public CorsFilter corsFilter() throws Exception {
return new CorsFilter();
}
You need to try this one
#Configuration
#EnableWebSocketMessageBroker
#EnableScheduling
public class WebSocketConfiguration implements WebSocketMessageBrokerConfigurer {
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/stomp").setAllowedOrigins("*");
}
}
I'm not sure about MVC, but when I faced this issue(While in development mode in ReactJs), I have used a Chrome Extension: Allow control allow origin, and it fixed the problem.
I'm trying to determine spring-boot, jersey and how the jersey and spring-boot contexts relate to one another.
#Component
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", "POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "x-requested-with");
chain.doFilter(req, res);
}
public void init(FilterConfig filterConfig) {
}
public void destroy() {
}
}
When I have it labeled a #Provider and make Jersey look in the package where it lives for it, it doesn't find it. It works when I make it a #Component.
#Configuration
#ApplicationPath("/api/v1")
public class JerseyConfig extends ResourceConfig{
public JerseyConfig() {
// DOESNT FIND MY CORSFilter as Provider
this.packages("com.mypackage.rest");
}
}
Does the #Configuration annotation make the JerseyContext a spring bean? And then spring injects the CORSFilter because it finds a component of Filter type? What is happening here?
You are implementing a servlet filter (implements Filter) which means that the servlet container is instantiating the filter. When you provide the #component annotation, still its the servlet container that initializes this filter. Its only that spring context is aware of this using the contextloader listener.
In jersey your filter should implement the ContainerRequestFilter or the ContainerResponseFilter so that the jersey configs are applied to the filters like URL path.
Since you used the servlet filter you should configure it manually.