Joker
Joker

Reputation: 2473

Spring - CORS not working with Security Config

I develop an angular app with a spring webflux backend. Up so far, the CorsFilter worked fine and allowed requests from the frontend.

Then I added a SecurityConfig. Since then the CorsFilter stopped working and I get an exception in the angular app:

Access to XMLHttpRequest at 'http://localhost:8080/users/999/folders/%2F/media/' from origin 'http://localhost:4200' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource

This filter worked fine:

@Configuration
public class CorsFilter {

    private static final String FRONTEND_LOCALHOST = "http://localhost:4200";
    private static final String FRONTEND_STAGING = "https://somehost.github.io";

    @Bean
    CorsWebFilter corsWebFilter() {
        CorsConfiguration corsConfig = new CorsConfiguration();
        corsConfig.applyPermitDefaultValues();
        corsConfig.addAllowedMethod(HttpMethod.PUT);
        corsConfig.addAllowedMethod(HttpMethod.DELETE);
        corsConfig.setAllowedOrigins(Arrays.asList(FRONTEND_LOCALHOST, FRONTEND_STAGING));

        UrlBasedCorsConfigurationSource source =
                new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", corsConfig);

        return new CorsWebFilter(source);
    }
}

Then I added authorization (bearer token) with following SecurityConfig:

@EnableWebFluxSecurity
@EnableReactiveMethodSecurity
public class SecurityConfiguration {

    @Bean
    public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
        http.cors().and().csrf()
            .csrfTokenRepository(CookieServerCsrfTokenRepository.withHttpOnlyFalse())
            .and()
            .authorizeExchange()
            .anyExchange().authenticated()
            .and()
            .oauth2ResourceServer()
            .jwt();
        return http.build();
    }

It seems with the security config my CorsFilter is not taken into account anymore. I red that the corsfilter needs to be added explicity in the config, but the examples I found didnt work. I hope somebody can help and knows why.

EDIT: To address the duplication concerns: I already tried adding cors() and cors().configurationSource(corsConfig()) into my security config, but didnt helped either.

Upvotes: 4

Views: 7499

Answers (2)

Joker
Joker

Reputation: 2473

I found a working way in Enable CORS in Spring 5 Webflux? by implementing a custom corsfilter.

However I still wasnt happy with the solution as it looked quite like a workaround.

Finally I found the culprit(s)... one is quite embarassing. My posted SecurityConfig was in the wrong package (it was in the default package by accident) and for this reason the config didnt picked up.

Also the cors filter from the question started working when I pasted the code to the securityconfig.

So my final SecurityConfig looks like this:

import java.util.Arrays;

import org.springframework.context.annotation.Bean;
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.security.web.server.csrf.CookieServerCsrfTokenRepository;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.reactive.CorsConfigurationSource;
import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource;

@EnableWebFluxSecurity
@EnableReactiveMethodSecurity
public class SecurityConfiguration {

    private static final String FRONTEND_LOCALHOST = "http://localhost:4200";
    private static final String FRONTEND_STAGING = "https://somehost.github.io";

    @Bean
    public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
        http
                .csrf()
                .csrfTokenRepository(CookieServerCsrfTokenRepository.withHttpOnlyFalse())
                .and()
                .authorizeExchange()
                .anyExchange().authenticated()
                .and()
                .oauth2ResourceServer()
                .jwt();
        return http.build();
    }


    @Bean
    CorsConfigurationSource corsConfiguration() {
        CorsConfiguration corsConfig = new CorsConfiguration();
        corsConfig.applyPermitDefaultValues();
        corsConfig.addAllowedMethod(HttpMethod.PUT);
        corsConfig.addAllowedMethod(HttpMethod.DELETE);
        corsConfig.setAllowedOrigins(Arrays.asList(FRONTEND_LOCALHOST, FRONTEND_STAGING));

        UrlBasedCorsConfigurationSource source =
                new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", corsConfig);
        return source;
    }
}

Upvotes: 13

Trần Quốc Vũ
Trần Quốc Vũ

Reputation: 467

try add this config

corsConfig.setAllowCredentials(true);

Upvotes: -1

Related Questions