【Spring Security】解決CORS跨域問題

最後更新日期:2024年08月24日

問題原因

解決方法

方法1.在Spring Security設定類別下,新增返回CorsConfigurationSource類別的createCorsConfig()方法,並加入SecurityFilterChain類別

     /**
     * 新增 Cors 設定
     * @return CorsConfigurationSource
     */
    private CorsConfigurationSource createCorsConfig(){
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowedOrigins(List.of("http://localhost:5173")); // 請求來源
        config.setAllowedHeaders(List.of("*")); // request header
        config.setAllowedMethods(List.of("*")); // http method

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

        return source;
    }
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {

        return http
                .csrf(csrf -> csrf.disable())
                .httpBasic(Customizer.withDefaults())
                .formLogin(Customizer.withDefaults())

                .authorizeHttpRequests(request -> request
                                .requestMatchers("/hello").authenticated()
                        .requestMatchers("/", "/register").permitAll()
                        .anyRequest().denyAll()
                )
                // 解決跨域問題
                .cors(cors -> cors.configurationSource(createCorsConfig()))
                .build();
    }

方法2.宣告一個返回CorsConfigurationSource類別為Bean的方法

/**
 * 解決 CORS 問題
 * @return CorsConfigurationSource
 */
@Bean
public CorsConfigurationSource corsConfigurationSource() {
    CorsConfiguration configuration = new CorsConfiguration();
    configuration.setAllowedOrigins(List.of("http://localhost:5173")); // 請求來源
    configuration.setAllowedHeaders(List.of("*")); // request header
    configuration.setAllowedMethods(List.of("*")); // http method
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    source.registerCorsConfiguration("/**", configuration);
    return source;
}

新增cors()方法,增加Spring提供的CorsFilter,避免401錯誤

Spring Security預期所有的API的request都有一個授權的token,因為preflight不會有攜帶token,而造成401錯誤(our API expects an authorization token in the OPTIONS request)

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    return http
            .csrf(csrf -> csrf.disable())
            .httpBasic(Customizer.withDefaults())
            .formLogin(Customizer.withDefaults())
            .authorizeHttpRequests(request -> request
                            .requestMatchers("/hello").authenticated()
                            .requestMatchers("/", "/register").permitAll()
                            .anyRequest().denyAll()
            )
            // 關閉Spring Security的授權檢查機制
            .cors(Customizer.withDefaults()) // disable this line to reproduce the CORS 401
            .build();
}

參考資料: Fixing 401s with CORS Preflights and Spring Security

參考資料

  1. CORS :: Spring Security
  2. 資安一把罩!Spring Security 零基礎入門
  3. Allow CORS with Spring Security 6.1.1 with authenticated requests

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *