CORS

Spring 框架提供 first class support for CORS 。在 Spring 安全之前必须处理 CORS,因为预检请求不包含任何 Cookie(即, JSESSIONID )。如果请求不包含任何 Cookie 且 Spring 安全在先,则该请求确定用户未通过认证(因为请求中没有 Cookie)并拒绝该请求。

Spring Framework provides first class support for CORS. CORS must be processed before Spring Security, because the pre-flight request does not contain any cookies (that is, the JSESSIONID). If the request does not contain any cookies and Spring Security is first, the request determines that the user is not authenticated (since there are no cookies in the request) and rejects it.

确保首先处理 CORS 的最简单方法是使用 CorsFilter。用户可以通过提供 CorsConfigurationSource 来将 CorsFilter 与 Spring Security 结合起来。例如,以下内容将在 Spring Security 中集成 CORS 支持:

The easiest way to ensure that CORS is handled first is to use the CorsFilter. Users can integrate the CorsFilter with Spring Security by providing a CorsConfigurationSource. For example, the following will integrate CORS support within Spring Security:

  • Java

  • Kotlin

@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;
}
@Bean
fun corsConfigurationSource(): CorsConfigurationSource {
    val configuration = CorsConfiguration()
    configuration.allowedOrigins = listOf("https://example.com")
    configuration.allowedMethods = listOf("GET", "POST")
    val source = UrlBasedCorsConfigurationSource()
    source.registerCorsConfiguration("/**", configuration)
    return source
}

以下清单在 XML 中执行相同的操作:

The following listing does the same thing in XML:

<http>
	<cors configuration-source-ref="corsSource"/>
	...
</http>
<b:bean id="corsSource" class="org.springframework.web.cors.UrlBasedCorsConfigurationSource">
	...
</b:bean>

如果你使用 Spring MVC 的 CORS 支持,你可以省略指定 CorsConfigurationSource,Spring Security 使用提供给 Spring MVC 的 CORS 配置:

If you use Spring MVC’s CORS support, you can omit specifying the CorsConfigurationSource and Spring Security uses the CORS configuration provided to Spring MVC:

  • Java

  • Kotlin

@Configuration
@EnableWebSecurity
public class WebSecurityConfig {

	@Bean
	public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
		http
			// if Spring MVC is on classpath and no CorsConfigurationSource is provided,
			// Spring Security will use CORS configuration provided to Spring MVC
			.cors(withDefaults())
			...
		return http.build();
	}
}
@Configuration
@EnableWebSecurity
open class WebSecurityConfig {
    @Bean
    open fun filterChain(http: HttpSecurity): SecurityFilterChain {
        http {
            // if Spring MVC is on classpath and no CorsConfigurationSource is provided,
            // Spring Security will use CORS configuration provided to Spring MVC
            cors { }
            // ...
        }
        return http.build()
    }
}

以下清单在 XML 中执行相同的操作:

The following listing does the same thing in XML:

<http>
	<!-- Default to Spring MVC's CORS configuration -->
	<cors />
	...
</http>

如果你有多个 CorsConfigurationSource Bean,Spring Security 不会自动为你配置 CORS 支持,这是因为它无法决定使用哪一个。如果你想为每个 SecurityFilterChain 指定不同的 CorsConfigurationSource,你可以将其直接传递到 .cors() DSL 中。

If you have more than one CorsConfigurationSource bean, Spring Security won’t automatically configure CORS support for you, that is because it cannot decide which one to use. If you want to specify different CorsConfigurationSource for each SecurityFilterChain, you can pass it directly into the .cors() DSL.

  • Java

  • Kotlin

@Configuration
@EnableWebSecurity
public class WebSecurityConfig {

	@Bean
	@Order(0)
	public SecurityFilterChain apiFilterChain(HttpSecurity http) throws Exception {
		http
			.securityMatcher("/api/**")
			.cors((cors) -> cors
				.configurationSource(apiConfigurationSource())
			)
			...
		return http.build();
	}

	@Bean
	@Order(1)
	public SecurityFilterChain myOtherFilterChain(HttpSecurity http) throws Exception {
		http
			.cors((cors) -> cors
				.configurationSource(myWebsiteConfigurationSource())
			)
			...
		return http.build();
	}

	CorsConfigurationSource apiConfigurationSource() {
		CorsConfiguration configuration = new CorsConfiguration();
		configuration.setAllowedOrigins(Arrays.asList("https://api.example.com"));
		configuration.setAllowedMethods(Arrays.asList("GET","POST"));
		UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
		source.registerCorsConfiguration("/**", configuration);
		return source;
	}

	CorsConfigurationSource myWebsiteConfigurationSource() {
		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;
	}

}
@Bean
fun corsConfigurationSource(): CorsConfigurationSource {
    val configuration = CorsConfiguration()
    configuration.allowedOrigins = listOf("https://example.com")
    configuration.allowedMethods = listOf("GET", "POST")
    val source = UrlBasedCorsConfigurationSource()
    source.registerCorsConfiguration("/**", configuration)
    return source
}