spring spring-boot spring-mvc spring-security cors

Spring Boot Security CORS



spring-boot spring-mvc (7)

Tengo un problema con el filtro CORS en las URL de seguridad de primavera. No establece Access-Control-Allow-Origin y otros encabezados expuestos en las URL que pertenecen a spring sec (inicio / cierre de sesión) o filtrados por Spring Security.

Aquí están las configuraciones.

CORS:

@Configuration @EnableWebMvc public class MyWebMvcConfig extends WebMvcConfigurerAdapter { ********some irrelevant configs************ @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/*").allowedOrigins("*").allowedMethods("GET", "POST", "OPTIONS", "PUT") .allowedHeaders("Content-Type", "X-Requested-With", "accept", "Origin", "Access-Control-Request-Method", "Access-Control-Request-Headers") .exposedHeaders("Access-Control-Allow-Origin", "Access-Control-Allow-Credentials") .allowCredentials(true).maxAge(3600); } }

Seguridad:

@Configuration @EnableWebSecurity public class OAuth2SecurityConfiguration extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .exceptionHandling().authenticationEntryPoint(authenticationEntryPoint).and() .formLogin() .successHandler(ajaxSuccessHandler) .failureHandler(ajaxFailureHandler) .loginProcessingUrl("/authentication") .passwordParameter("password") .usernameParameter("username") .and() .logout() .deleteCookies("JSESSIONID") .invalidateHttpSession(true) .logoutUrl("/logout") .logoutSuccessUrl("/") .and() .csrf().disable() .anonymous().disable() .authorizeRequests() .antMatchers("/authentication").permitAll() .antMatchers("/oauth/token").permitAll() .antMatchers("/admin/*").access("hasRole(''ROLE_ADMIN'')") .antMatchers("/user/*").access("hasRole(''ROLE_USER'')"); } }

Entonces, si hago una solicitud a las URL que no son escuchadas por la seguridad, se configuran los encabezados CORS. URL de seguridad de Spring: no configurada.

Spring boot 1.4.1


Opción 1 (Usar WebMvcConfigurer bean):

La configuración CORS con la que comenzó no es la forma correcta de hacerlo con Spring Boot. WebMvcConfigurer registrar un bean WebMvcConfigurer . Referencia here

Ejemplo de configuración de Spring Boot CORS:

@Configuration @Profile("dev") public class DevConfig { @Bean public WebMvcConfigurer corsConfigurer() { return new WebMvcConfigurerAdapter() { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**").allowedOrigins("http://localhost:4200"); } }; } }

Esto proporcionará la configuración CORS para una aplicación Spring Boot básica (sin iniciador de seguridad). Tenga en cuenta que el soporte CORS existe independientemente de Spring Security.

Una vez que introduce Spring Security, debe registrar CORS con su configuración de seguridad. Spring Security es lo suficientemente inteligente como para recoger su configuración CORS existente.

@Override protected void configure(HttpSecurity http) throws Exception { http .cors().and() ....

Opción 2 (Usar el bean CorsConfigurationSource):

La primera opción que describí es realmente desde la perspectiva de agregar Spring Security a una aplicación existente. Si está agregando Spring Security desde el primer momento, la forma que se describe en los Documentos de Spring Security involucra agregar un bean CorsConfigurationSource.

@EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http // by default uses a Bean by the name of corsConfigurationSource .cors().and() ... } @Bean CorsConfigurationSource corsConfigurationSource() { CorsConfiguration configuration = new CorsConfiguration(); configuration.setAllowedOrigins(Arrays.asList("https://example.com")); configuration.setAllowedMethods(Arrays.asList("GET","POST")); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", configuration); return source; } }


Acabo de tener un problema similar, estaba tratando de ejecutar una solicitud desde mi interfaz en React ejecutándose en http: // localhost: 3000 , a mi backend en SpringBoot ejecutándose en http: // localhost: 8080 . Tuve dos errores:

Control de acceso Permitir origen

Resolví esto muy fácilmente agregando esto a mi RestController:

@CrossOrigin(origins = ["http://localhost:3000"])

Después de solucionar esto, comencé a recibir este error: el valor del encabezado ''Access-Control-Allow-Credentials'' en la respuesta es '''', que debe ser ''verdadero''

Acceso-Control-Permitir-Credenciales

Este puede solucionarse de dos maneras:

  1. Agregar allowCredentials = "true" a la configuración de CrossOrigin:

    @CrossOrigin(origins = ["http://localhost:3000"], allowCredentials = "true")

  2. Cambiar las opciones de credenciales de la búsqueda en la solicitud de interfaz. Básicamente, deberá realizar la llamada de recuperación de esta manera:

    fetch(''http://localhost:8080/your/api'', { credentials: ''same-origin'' })

Espero que esto ayude =)


Actualmente, las solicitudes de OPTIONS están bloqueadas de forma predeterminada si la seguridad está habilitada.

Simplemente agregue un bean adicional y las solicitudes de verificación previa se manejarán correctamente:

@Bean public IgnoredRequestCustomizer optionsIgnoredRequestsCustomizer() { return configurer -> { List<RequestMatcher> matchers = new ArrayList<>(); matchers.add(new AntPathRequestMatcher("/**", "OPTIONS")); configurer.requestMatchers(new OrRequestMatcher(matchers)); }; }

Tenga en cuenta que, dependiendo de su aplicación, esto puede abrirlo para posibles exploits.

Problema abierto para una mejor solución: https://github.com/spring-projects/spring-security/issues/4448


En lugar de utilizar CorsRegistry, puede escribir su propio CorsFilter y agregarlo a su configuración de seguridad.

Clase CorsFilter personalizada:

public class CorsFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletResponse response = (HttpServletResponse) servletResponse; HttpServletRequest request= (HttpServletRequest) servletRequest; response.setHeader("Access-Control-Allow-Origin", "*"); response.setHeader("Access-Control-Allow-Methods", "GET,POST,DELETE,PUT,OPTIONS"); response.setHeader("Access-Control-Allow-Headers", "*"); response.setHeader("Access-Control-Allow-Credentials", true); response.setHeader("Access-Control-Max-Age", 180); filterChain.doFilter(servletRequest, servletResponse); } @Override public void destroy() { } }

Clase de configuración de seguridad:

@Configuration @EnableWebSecurity public class OAuth2SecurityConfiguration extends WebSecurityConfigurerAdapter { @Bean CorsFilter corsFilter() { CorsFilter filter = new CorsFilter(); return filter; } @Override protected void configure(HttpSecurity http) throws Exception { http .addFilterBefore(corsFilter(), SessionManagementFilter.class) //adds your custom CorsFilter .exceptionHandling().authenticationEntryPoint(authenticationEntryPoint).and() .formLogin() .successHandler(ajaxSuccessHandler) .failureHandler(ajaxFailureHandler) .loginProcessingUrl("/authentication") .passwordParameter("password") .usernameParameter("username") .and() .logout() .deleteCookies("JSESSIONID") .invalidateHttpSession(true) .logoutUrl("/logout") .logoutSuccessUrl("/") .and() .csrf().disable() .anonymous().disable() .authorizeRequests() .antMatchers("/authentication").permitAll() .antMatchers("/oauth/token").permitAll() .antMatchers("/admin/*").access("hasRole(''ROLE_ADMIN'')") .antMatchers("/user/*").access("hasRole(''ROLE_USER'')"); } }


Si lo necesita para un desarrollo local rápido, simplemente agregue esta anotación en su controlador. (fuera de curso cambiar los orígenes según sea necesario)

@ResponseStatus ( value = HttpStatus.NO_CONTENT ) public class CorsException extends RuntimeException { }


También puede lograr esto con un interceptor.

Use la excepción para asegurarse de que está finalizando el ciclo de vida de la solicitud:

public class CorsMiddleware extends HandlerInterceptorAdapter { @Override public boolean preHandle ( HttpServletRequest request, HttpServletResponse response, Object handler ) throws Exception { if (request.getMethod().equals("OPTIONS")) { response.addHeader("Access-Control-Allow-Origin", "*"); response.addHeader("Access-Control-Allow-Credentials", "true"); response.addHeader("Access-Control-Allow-Methods","GET, POST, PUT, OPTIONS, DELETE"); response.addHeader("Access-Control-Allow-Headers", "DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,Authorization,If-Modified-Since,Cache-Control,Content-Type"); response.addHeader("Access-Control-Max-Age", "3600"); response.addHeader("charset", "utf-8"); throw new CorsException(); } return super.preHandle(request, response, handler); } }

Luego, en su interceptor, establezca encabezados para todas las solicitudes de OPTIONS y arroje la excepción:

@Configuration public class MiddlewareConfig extends WebMvcConfigurerAdapter { @Override public void addInterceptors (InterceptorRegistry registry) { registry.addInterceptor(new CorsMiddleware()) .addPathPatterns("/**"); } }

Por último, aplique el interceptor a todas las rutas:

@CrossOrigin(origins = "http://localhost:4200", maxAge = 3600)


Tengo un cliente web basado en React , y mi API REST de back-end está ejecutando Spring Boot Ver 1.5.2

Quería habilitar CORS rápidamente en todas las solicitudes de ruta del controlador de mi cliente que se ejecuta en localhost:8080 . Dentro de mi configuración de seguridad, simplemente agregué un @Bean de tipo FilterRegistrationBean y lo FilterRegistrationBean funcionar fácilmente.

Aquí está el código:

@Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) public class AuthConfiguration extends WebSecurityConfigurerAdapter { .... .... @Bean public FilterRegistrationBean corsFilter() { final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); CorsConfiguration config = new CorsConfiguration(); config.setAllowCredentials(true); config.addAllowedOrigin(corsAllowedOrigin); // @Value: http://localhost:8080 config.addAllowedHeader("*"); config.addAllowedMethod("*"); source.registerCorsConfiguration("/**", config); FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source)); bean.setOrder(0); return bean; } @Override protected void configure(HttpSecurity httpSecurity) throws Exception { httpSecurity .authorizeRequests() .antMatchers(HttpMethod.OPTIONS, "/**").permitAll() // **permit OPTIONS call to all** .... } .... .... }

Puede consultar los documentos de Spring Boot aquí