一、为什么要自定义cors配置
在使用Spring框架时,Spring Security组件提供了简便的cors配置方案,使程序开发者可以快速的实现“同源安全策略”。关于cors,可以参数之前的一篇文章--关于Spring Security的CORS_springsecurity cors-CSDN博客
由于cors涉及到URL 的协议(Protocol)、主机(Host)、端口(Port,这些东西在每个程序上的情况不同,所以一般情况下都是需要根据实际情况来定制适合的cors配置。
二、配置原理
我们可以先看下Spring Security组件的一个源码。
org.springframework.security.config.annotation.web.configurers.CorsConfigurer.class
@Override
public void configure(H http) {
ApplicationContext context = http.getSharedObject(ApplicationContext.class);
CorsFilter corsFilter = getCorsFilter(context);
Assert.state(corsFilter != null, () -> "Please configure either a " + CORS_FILTER_BEAN_NAME + " bean or a "
+ CORS_CONFIGURATION_SOURCE_BEAN_NAME + "bean.");
http.addFilter(corsFilter);
}
private CorsFilter getCorsFilter(ApplicationContext context) {
if (this.configurationSource != null) {
return new CorsFilter(this.configurationSource);
}
boolean containsCorsFilter = context.containsBeanDefinition(CORS_FILTER_BEAN_NAME);
if (containsCorsFilter) {
return context.getBean(CORS_FILTER_BEAN_NAME, CorsFilter.class);
}
boolean containsCorsSource = context.containsBean(CORS_CONFIGURATION_SOURCE_BEAN_NAME);
if (containsCorsSource) {
CorsConfigurationSource configurationSource = context.getBean(CORS_CONFIGURATION_SOURCE_BEAN_NAME,
CorsConfigurationSource.class);
return new CorsFilter(configurationSource);
}
if (mvcPresent) {
return MvcCorsFilter.getMvcCorsFilter(context);
}
return null;
}
这段源码简单、清晰,两个方法,一个公有,一个私有。configure(H http)被外部调用,实现了两件事,获取一个corsFilter(过滤器)并把这个filter添加到传入的这个名为“http”的对象中。这里也刚好能看出Configurer和Filter的一些关系--configurer会在拿到filter后,通过addFilter(filter)方法将一个filter添加到HttpSecurity对象中。
再看下getCorsFilter(ApplicationContext context)方法,4个if分支,最终的任务就是new一个CorsFilter并返回。所以自定义cors配置时,可以选择的方法有很多,这里选择创建一个CorsConfigurationSource类型的Bean。这里的getBean方法参数是name和type。所以我们在创建这个Bean的时候,需要确保Bean的名称为“corsConfigurationSource”(CORS_CONFIGURATION_SOURCE_BEAN_NAME对应的字符串),不然这里的getBean会找不到我们自定义创建的CorsConfigurationSource。
三、自定义配置
@Configuration
public class SecurityConfig {
/**
* 跨域资源共享过滤器
*/
@Autowired
@Bean
public CorsFilter corsFilter(UrlBasedCorsConfigurationSource configurationSource){
return new CorsFilter(configurationSource);
}
/**
* 跨域资源共享过滤器配置
*/
@Bean
public UrlBasedCorsConfigurationSource corsConfigurationSource(){
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.setAllowCredentials(true);
corsConfiguration.addAllowedHeader("*");
corsConfiguration.addAllowedMethod("*");
corsConfiguration.addAllowedOriginPattern("http://localhost*");
source.registerCorsConfiguration("/**",corsConfiguration);
return source;
}
}
几个要注意的地方:
1、类名上方的@Configuration注解,这个是为了指定该类为配置类,Spring容器启动时,会调用带有@Bean注解的方法来生成对应实例,并将实例注册为与方法名相同的Bean,并管理起来。
2、方法名,第1点说了,注册的Bean名称是和方法名一致的,所以这里的方法名需要是“corsConfigurationSource”,不能自定义方法名。
3、上面代码中的corsFilter()方法,可以不写。因为从前面的Spring Security源码中可以看出,如果没有这个corsFilter的Bean,它也会自己new一个。如果要自定义corsFilter,同样要注意方法名。至于参数,如果有带,需要注意参数类型(参数名可以任意),并在方法名上方多带一个@Autowired注解,这个注解会自动找到类型为UrlBasedCorsConfigurationSource的Bean,并使用它。如果不带参数,那也可以用普通方法,先获取corsConfigurationSource()方法返回的对象,再以些为参数,new一个corsFilter对象。