2

I am trying to write an application that uses Springs WebFlux Security. On the front-end angular application I am taking the user to a login page and once they are logged in the application should redirect to a different uri. As of right now I am getting this error:

     Failed to load http://localhost:8080/login: Redirect from 
     'http://localhost:8080/login' to 'http://localhost:8080/pets' has been 
     blocked by CORS policy: No 'Access-Control-Allow-Origin' header is 
     present on the requested resource. Origin 'http://localhost:4200' is 
     therefore not allowed access.

Currently I am not sure why I am having a CORS error but here is what I have for the spring webflux security

@EnableWebFluxSecurity
public class SecurityConfig {

@Autowired
private ReactiveUserDetailsService reactiveUserDetailsService;

@Bean
public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
    http
            .authorizeExchange()
            .pathMatchers(HttpMethod.POST, "/login").permitAll()
            .pathMatchers(HttpMethod.POST, "/logout").permitAll()
            .pathMatchers(HttpMethod.POST, "/register").permitAll()
            .anyExchange().authenticated()
            .and()
            .httpBasic().disable()
            .csrf().disable()
            .formLogin()
            .authenticationManager(authenticationManager())
            .requiresAuthenticationMatcher(ServerWebExchangeMatchers.pathMatchers(HttpMethod.POST, "/login"))
            .authenticationSuccessHandler(new RedirectServerAuthenticationSuccessHandler("/pets"))
            .authenticationFailureHandler(new ServerAuthenticationEntryPointFailureHandler(new HttpBasicServerAuthenticationEntryPoint()))
            .authenticationEntryPoint(new HttpBasicServerAuthenticationEntryPoint())
            .and()
            .logout()
            .logoutSuccessHandler(((exchange, authentication) -> Mono.fromRunnable(() -> exchange.getExchange().getResponse().setStatusCode(HttpStatus.OK))));

    return http.build();
}

@Bean
public ReactiveAuthenticationManager authenticationManager() {
    UserDetailsRepositoryReactiveAuthenticationManager authManager =
            new UserDetailsRepositoryReactiveAuthenticationManager(reactiveUserDetailsService);

    authManager.setPasswordEncoder(passwordEncoder());
    return authManager;
}

@Bean
PasswordEncoder passwordEncoder() {
    return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}
}

Is there something that I am missing or need to edit?

shahidfoy
  • 1,951
  • 1
  • 17
  • 23

3 Answers3

4

I had this issue and I was using this combination: Spring Boot + Webflux + Security.

  • Controller @CrossOrigin didn't work
  • Global CrossDomain, like the ones set in previous answers didn't work neither

The only solution that worked for me is documented here:

Enable CORS in Spring 5 Webflux?

  • Create a SecurityConfiguration class

  • The key to make CORS work using this combination is configuration.applyPermitDefaultValues();

  • If you remove that line, it won't work

    import org.springframework.context.annotation.Bean;
      import org.springframework.context.annotation.Configuration;
      import org.springframework.http.HttpMethod;
      import org.springframework.security.config.annotation.method.configuration.EnableReactiveMethodSecurity;
      import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
      import org.springframework.security.config.web.server.ServerHttpSecurity;
      import org.springframework.security.web.server.SecurityWebFilterChain;
      import org.springframework.web.cors.CorsConfiguration;
      import org.springframework.web.cors.reactive.CorsConfigurationSource;
      import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource;
    
      import java.util.Arrays;
    
      @Configuration
      @EnableWebFluxSecurity
      @EnableReactiveMethodSecurity
      public class SecurityConfiguration {
    
      @Bean
      public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
          System.out.println("Security Config");
    
          http
                  .csrf().disable()
                  .cors().configurationSource( corsConfigurationSource() ).and()
                  .authorizeExchange()
                  .pathMatchers(HttpMethod.POST, "/auth", "/api").permitAll()
                  .pathMatchers(HttpMethod.GET,"/**").permitAll()
                  .anyExchange().authenticated();
    
          return http.build();
      }
    
      @Bean
      CorsConfigurationSource corsConfigurationSource() {
          CorsConfiguration configuration = new CorsConfiguration();
          configuration.setAllowedOrigins(Arrays.asList("http://localhost:4200"));
          configuration.setAllowedMethods(Arrays.asList("GET","POST"));
          configuration.setMaxAge(3600L);
          configuration.applyPermitDefaultValues();
          UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
          source.registerCorsConfiguration("/**", configuration);
          return source;
      }
    

    }

lalvar
  • 71
  • 3
  • I tested other solutions and the one you linked worked fine. But when Spring Security is present in your pom.xml other solutions won't work except yours. Thank you for sharing this solition. – Ramdane Oualitsen Dec 31 '21 at 21:05
  • Worked from the first time after 2 days of trying. Thanks for sharing! – Vattic May 21 '22 at 19:27
1

You should define CORS mapping in a configuration for your Spring application.

Here is my sample:

@Configuration
@EnableWebFlux
@Import({CoreConfiguration.class, SecurityConfiguration.class})
public class ServicesConfiguration implements WebFluxConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {

        registry.addMapping("/api/**")
                .allowedOrigins("*")
                .allowedMethods("*")
                .allowedHeaders("*")
                .exposedHeaders("Access-Control-Allow-Origin",
                        "Access-Control-Allow-Methods",
                        "Access-Control-Allow-Headers",
                        "Access-Control-Max-Age",
                        "Access-Control-Request-Headers",
                        "Access-Control-Request-Method")
                .maxAge(3600);

        // Add more mappings...
    }
}

The fact is that if I test requests from Postman, there are no CORS issues, it appears when the frontend (actually the browser) need proper CORS headers.

References:

nghiaht
  • 775
  • 4
  • 12
0

You have done completely right but you need to configure your port 8080 as proxy port .

Just simply create a new file called proxy.conf.json in the root of the project and inside of that define your proxies like below.

{
  "/login": {
     "target":  {
       "host": "localhost",
       "protocol": "http:",
       "port": 8080
     },
     "secure": false,
     "changeOrigin": true,
     "logLevel": "info"
  }
}

similarly you can bind another url also .

Now in the next step just when you run your angular app .Make the following command .

ng serve --proxy-config proxy.conf.json

this_is_om_vm
  • 608
  • 5
  • 23