La solicitud de Spring Boot Preflight no pasa la verificación de control de acceso

2020-06-30 spring-boot spring-security

Estoy usando Spring Boot y Spring Security en mi aplicación web. Ahora tengo un punto final / api / login y la interfaz simplemente publica el nombre de usuario y la contraseña en el cuerpo de la solicitud para obtener un JWT.

Pero constantemente estoy recibiendo

Access to fetch at 'http://localhost:8081/api/login' from origin 'http://localhost:3001' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: It does not have HTTP ok status.

Ya agregué @CrossOrigin (origins = "*", maxAge = 3600) en la clase de controlador para resolver el problema de cors, por lo que ahora http get funciona bien. Pero todas las publicaciones no funcionaron debido a la verificación previa. También intenté

.requestMatchers(CorsUtils::isPreFlightRequest).permitAll()

y

.and().cors();

en mi WebSecurityConfigurerAdapter, pero ninguno de ellos resuelve el problema. ¿Qué debería hacer después?

Aquí está la clase de configuración completa:

package com.cyf.myblogserver.config;

import com.cyf.myblogserver.component.JwtRequestFilter;
import com.cyf.myblogserver.service.BlogUserDetailsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsUtils;

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private BlogUserDetailsService BlogUserDetailsService;
    @Autowired
    JwtRequestFilter jwtRequestFilter;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(BlogUserDetailsService);
    }

    @Bean
    public PasswordEncoder passwordEncoder(){
        return NoOpPasswordEncoder.getInstance();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
                .authorizeRequests()
                .requestMatchers(CorsUtils::isPreFlightRequest).permitAll()
                .antMatchers(HttpMethod.POST,"/api/token").permitAll()
                .antMatchers(HttpMethod.GET, "/api/articles").permitAll()
                .anyRequest().authenticated().and().cors();
        http.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
        http.headers().cacheControl();
    }

    @Bean
    public AuthenticationManager customAuthenticationManager() throws Exception {
        return authenticationManager();
    }
}

Answers

Si está utilizando Spring Security, tenga una configuración global para sus equipos como:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception { 
         http.
         cors().and().csrf().disable()
                .authorizeRequests()                                                                
                .antMatchers("/**").permitAll()
                .antMatchers("/login").hasRole("ADMIN")                                      
                .antMatchers("/Signup").hasRole("USER")
                .and() //add rest of your configurations
    }

    @Bean   
    public CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(Arrays.asList("http://localhost:3001")); //or add * to allow all origins
        configuration.setAllowCredentials(true);
        configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS")); //to set allowed http methods
        configuration.setAllowedHeaders(Arrays.asList("Authorization", "Cache-Control", "Content-Type"));
        configuration.setExposedHeaders(Arrays.asList("custom-header1", "custom-header2"));
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration); 
        return source; 
    }
}

Cuando proporciona una configuración como esta a nivel mundial, el código es mucho más limpio y también puede proporcionar las configuraciones como desee y será aplicable a todos los controladores y sus métodos. Asegúrese de que las configuraciones automáticas de Spring funcionen, estamos proporcionando el bean de configuración cors y habilitando cors en la seguridad del resorte, por lo que si la configuración automática funciona, Spring usará automáticamente el bean cors que creamos con nuestras configuraciones.

Related