Spring Data Rest and Cors
Indeed, before Spring Data REST 2.6 (Ingalls) only HandlerMapping
instances created by Spring MVC WebMvcConfigurationSupport
and controllers annotated with @CrossOrigin
were CORS aware.
But now that DATAREST-573 has been fixed, RepositoryRestConfiguration
now exposes a getCorsRegistry()
for global setup and @CrossOrigin
annotations on repositories are also recognized so this is the recommended approach. See https://stackoverflow.com/a/42403956/1092077 answer for concrete examples.
For people that have to stick to Spring Data REST 2.5 (Hopper) or previous versions, I think the best solution is to use a filter based approach. You could obviously use Tomcat, Jetty or this one, but be aware that Spring Framework 4.2 also provides a CorsFilter
that use the same CORS processing logic that @CrossOrigin
and addCorsMappings(CorsRegistry registry)
approaches. By passing an UrlBasedCorsConfigurationSource
instance to the CorsFilter
constructor parameter, you could easily get something as powerful as Spring native CORS global support.
If you are using Spring Boot (which supports Filter
beans), it could be something like:
@Configuration
public class RestConfiguration {
@Bean
public FilterRegistrationBean corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration().applyPermitDefaultValues();
source.registerCorsConfiguration("/**", config);
FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
bean.setOrder(0);
return bean;
}
}
CORS exception with Spring Data Rest + Spring Security when posting via '/login' path but other paths are fine
I figured out the issue. This relates to the cors configuration in Spring Security. If you use web, the browser changed the POST request into an OPTIONS request, therefore blocked by the default CORS configuration because there default does not allow OPTION requests
override fun configure(http: HttpSecurity?) {
http {
csrf {
disable()
}
cors {} //Enable CORS here
sessionManagement {
sessionCreationPolicy = SessionCreationPolicy.STATELESS
}
addFilterAt<UsernamePasswordAuthenticationFilter>(
JwtUsernameAndPasswordAuthenticationFilter(
authenticationManager(),
jwtConfiguration,
secretKey,
repository
)
)
addFilterAfter<JwtUsernameAndPasswordAuthenticationFilter>(JwtTokenVerifier(jwtConfiguration, secretKey))
authorizeRequests {
authorize(anyRequest, permitAll)
}
}
}
Configure your CORS here
@Bean
fun corsConfigurationSource(): CorsConfigurationSource {
val configuration = CorsConfiguration()
configuration.allowedOrigins = listOf("https://example.com")
configuration.allowedMethods = listOf("*") //Allow all http methods
val source = UrlBasedCorsConfigurationSource()
source.registerCorsConfiguration("/**", configuration)
return source
}
This is no longer needed after implementing CORS in Spring Security
@Component
class AppRepositoryRestConfigurer : RepositoryRestConfigurer {
override fun configureRepositoryRestConfiguration(config: RepositoryRestConfiguration?, cors: CorsRegistry?) {
cors?.addMapping("/**")?.allowedOriginPatterns("http://localhost:[*]")
}
}
How do i add CORS to /profile endpoint exposed by spring data rest
The simplest approach is to add a @CrossOrign("*")
annotation above the controller class.
edit
Another approch is to enable CORS globally, by exposing this bean:
@Bean
public CorsFilter corsFilter() {
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
final CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
// Don't do this in production, use a proper list of allowed origins
config.setAllowedOrigins(Collections.singletonList("*"));
config.setAllowedHeaders(Arrays.asList("Origin", "Content-Type", "Accept"));
config.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "OPTIONS", "DELETE", "PATCH"));
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
CORS header ‘Access-Control-Allow-Origin’ missing with Spring Data REST
I don't know why the other configs are not taken into account and I don't know if this is considered a good solution but since I only need this on the local environment it is not that important. This is how I got this working:
@Bean
@Profile("local")
open fun corsConfigurationSource(): CorsConfigurationSource{
val cors = UrlBasedCorsConfigurationSource()
val config = CorsConfiguration().applyPermitDefaultValues()
config.addAllowedMethod(HttpMethod.OPTIONS)
config.addAllowedMethod(HttpMethod.POST)
config.addAllowedMethod(HttpMethod.PATCH)
config.addAllowedMethod(HttpMethod.DELETE)
cors.registerCorsConfiguration("/**", config)
return cors
}
Spring Boot Data Rest + CORS not being enabled properly for OPTIONS/DELETE
This is what I use as a permit all CORS servlet filter:
public class PermissiveCORSFilter implements Filter {
private static final Logger LOGGER = LoggerFactory.getLogger(PermissiveCORSFilter.class);
private static final Pattern PATTERN = Pattern.compile("^[a-zA-Z0-9 ,-_]*$");
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
HttpServletRequest request = (HttpServletRequest) req;
String origin;
String credentialFlag;
if (request.getHeader("Origin") == null) {
origin = "*";
credentialFlag = "false";
} else {
origin = request.getHeader("Origin");
credentialFlag = "true";
}
// need to do origin.toString() to avoid findbugs error about response splitting
response.addHeader("Access-Control-Allow-Origin", origin.toString());
response.setHeader("Access-Control-Allow-Credentials", credentialFlag);
if ("OPTIONS".equals(request.getMethod())) {
LOGGER.info("Received OPTIONS request from origin:" + request.getHeader("Origin"));
response.setHeader("Access-Control-Allow-Methods", "GET,POST,HEAD,OPTIONS,PUT,DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
String headers = StringUtils.trimToEmpty(request.getHeader("Access-Control-Request-Headers"));
if (!PATTERN.matcher(headers).matches()) {
throw new ServletException("Invalid value provided for 'Access-Control-Request-Headers' header");
}
response.setHeader("Access-Control-Allow-Headers", headers); // allow any headers
}
chain.doFilter(req, res);
}
@Override
public void init(FilterConfig filterConfig) {
// Do nothing
}
@Override
public void destroy() {
// Do nothing
}
Enabling cross origin requests in Spring Data Rest
I've used my custom CORS filter to make it work:
/**
* Filter for enabling CORS support.
*/
@Component
public class CorsFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(final HttpServletRequest request, final HttpServletResponse response,
final FilterChain filterChain) throws ServletException, IOException {
response.addHeader("Access-Control-Allow-Origin", "*");
response.addHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT, PATCH, HEAD, OPTIONS");
response.addHeader("Access-Control-Allow-Headers", "Origin, Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers");
response.addHeader("Access-Control-Expose-Headers", "Access-Control-Allow-Origin, Access-Control-Allow-Credentials");
response.addHeader("Access-Control-Allow-Credentials", "true");
response.addIntHeader("Access-Control-Max-Age", 10);
filterChain.doFilter(request, response);
}
}
Related Topics
How to Update a Textview of an Activity from Another Class
How to Find the Currently Running Applications Programmatically in Android
How to Click an Element in Selenium Webdriver Using JavaScript
Webview and Cookies on Android
Android: Sending Data >20 Bytes by Ble
How to Add Image in a Textview Text
What Is Shareduserid in Android, and How Is It Used
Android Studio Debugger Highlights the Wrong Lines
How to Pass a String from One Activity to Another
How to Change Color of the Back Arrow in the New Material Theme
How to Delete Stuff Printed to Console by System.Out.Println()