概述
介绍
作为一个配置HttpSecurity
的SecurityConfigurer
,CorsConfigurer
的配置任务如下 :
- 配置如下安全过滤器
Filter
CorsFilter
- 如果
CorsConfigurer
上设置了属性configurationSource
,则基于它创建一个CorsFilter
并使用; - 否则如果名称为
corsFilter
的bean
存在,则使用该CorsFilter
; - 否则如果名称为
corsConfigurationSource
的bean
存在,则基于它创建一个CorsFilter
并使用; - 否则如果名称为
mvcHandlerMappingIntrospector
的bean
存在,则基于它创建一个CorsFilter
并使用。名称为
mvcHandlerMappingIntrospector
的bean
存在表明Spring MVC
被使用,因为使用了Spring MVC
的话,Spring MVC
的配置机制(WebMvcConfigurationSupport
)会注册一个类型为HandlerMappingIntrospector
名称为mvcHandlerMappingIntrospector
的bean
到容器。
- 如果
继承关系
使用
// HttpSecurity 代码片段
public CorsConfigurer<HttpSecurity> cors() throws Exception {
return getOrApply(new CorsConfigurer<>());
}
源代码
源代码版本 Spring Security Config 5.1.4.RELEASE
package org.springframework.security.config.annotation.web.configurers;
// 省略 imports
public class CorsConfigurer<H extends HttpSecurityBuilder<H>>
extends AbstractHttpConfigurer<CorsConfigurer<H>, H> {
private static final String HANDLER_MAPPING_INTROSPECTOR =
"org.springframework.web.servlet.handler.HandlerMappingIntrospector";
private static final String CORS_CONFIGURATION_SOURCE_BEAN_NAME = "corsConfigurationSource";
private static final String CORS_FILTER_BEAN_NAME = "corsFilter";
private CorsConfigurationSource configurationSource;
/**
* Creates a new instance
*
* @see HttpSecurity#cors()
*/
public CorsConfigurer() {
}
public CorsConfigurer<H> configurationSource(
CorsConfigurationSource configurationSource) {
this.configurationSource = configurationSource;
return this;
}
@Override
public void configure(H http) throws Exception {
ApplicationContext context = http.getSharedObject(ApplicationContext.class);
CorsFilter corsFilter = getCorsFilter(context);
if (corsFilter == null) {
throw new IllegalStateException(
"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);
}
boolean mvcPresent = ClassUtils.isPresent(HANDLER_MAPPING_INTROSPECTOR,
context.getClassLoader());
if (mvcPresent) {
return MvcCorsFilter.getMvcCorsFilter(context);
}
return null;
}
static class MvcCorsFilter {
private static final String HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME =
"mvcHandlerMappingIntrospector";
/**
* This needs to be isolated into a separate class as Spring MVC is an optional
* dependency and will potentially cause ClassLoading issues
* @param context
* @return
*/
private static CorsFilter getMvcCorsFilter(ApplicationContext context) {
if (!context.containsBean(HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME)) {
throw new NoSuchBeanDefinitionException(HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME,
"A Bean named " + HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME +" of type "
+ HandlerMappingIntrospector.class.getName()
+ " is required to use MvcRequestMatcher. Please ensure Spring Security & Spring MVC "
+ "are configured in a shared ApplicationContext.");
}
HandlerMappingIntrospector mappingIntrospector =
context.getBean(HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME,
HandlerMappingIntrospector.class);
return new CorsFilter(mappingIntrospector);
}
}
}