Spring Security Config : HttpSecurity安全配置器 CorsConfigurer

本文深入解析了Spring Security中CorsConfigurer的配置逻辑与实现细节,包括如何通过不同的方式配置CorsFilter,以及与SpringMVC的集成关系。

概述

介绍

作为一个配置HttpSecuritySecurityConfigurer,CorsConfigurer的配置任务如下 :

  • 配置如下安全过滤器Filter
    • CorsFilter
      1. 如果CorsConfigurer上设置了属性configurationSource,则基于它创建一个CorsFilter并使用;
      2. 否则如果名称为corsFilterbean存在,则使用该CorsFilter;
      3. 否则如果名称为corsConfigurationSourcebean存在,则基于它创建一个CorsFilter并使用;
      4. 否则如果名称为mvcHandlerMappingIntrospectorbean存在,则基于它创建一个CorsFilter并使用。

        名称为mvcHandlerMappingIntrospectorbean存在表明Spring MVC被使用,因为使用了Spring MVC的话,Spring MVC的配置机制(WebMvcConfigurationSupport)会注册一个类型为HandlerMappingIntrospector名称为mvcHandlerMappingIntrospectorbean到容器。

继承关系

CorsConfigurer

使用

	// 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);
		}
	}
}

参考文章

在前后端分离的架构中,Spring Security 配置 CORS(跨域资源共享)是确保前后端能够正常通信的关键步骤。由于前后端分离通常涉及跨域请求,Spring Security 必须明确允许这些请求通过 CORS 配置[^1]。 ### 配置 CORS 的方式 为了支持前后端分离架构,需要在 Spring Security 中配置 `CorsRegistry`,指定允许的来源、方法、头部信息等。以下是一个典型的配置示例: ```java @Configuration @EnableWebSecurity public class SecurityConfig { @Bean public WebMvcConfigurer corsConfigurer() { return new WebMvcConfigurer() { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/api/**") .allowedOrigins("http://localhost:8080") .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") .allowedHeaders("Content-Type", "Authorization") .exposedHeaders("X-Custom-Header") .allowCredentials(true); } }; } } ``` 上述配置中,`/api/**` 是后端 API 的路径,`allowedOrigins` 指定了允许的前端域名,`allowedMethods` 列出了允许的 HTTP 方法,`allowedHeaders` 指定了允许的请求头,`exposedHeaders` 指定了前端可以访问的响应头,`allowCredentials` 允许携带凭据(如 Cookie)。 ### Spring Security 中的 CORS 处理 除了全局的 CORS 配置,还需要确保 Spring Security安全配置中正确处理 CORS 请求。可以通过 `HttpSecurity` 的 `cors()` 方法启用 CORS 支持: ```java @Override protected void configure(HttpSecurity http) throws Exception { http .cors().and() .csrf().disable() .authorizeRequests() .anyRequest().authenticated(); } ``` 上述配置中,`cors()` 启用了 Spring Security 对 CORS 的支持,确保跨域请求能够被正确处理。同时,`csrf().disable()` 禁用了 CSRF 保护,适用于前后端分离、基于 Token 的认证方式。 ### 预检请求(OPTIONS)处理 在跨域请求中,浏览可能会发送预检请求(OPTIONS),以确认服务是否允许实际请求。Spring Security 默认会处理 OPTIONS 请求,但需要确保返回的响应头中包含必要的 CORS 信息。如果使用了自定义过滤,可以手动处理 OPTIONS 请求: ```java @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { if ("OPTIONS".equals(request.getMethod())) { response.setHeader("Access-Control-Allow-Origin", "http://localhost:8080"); response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS"); response.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization"); response.setHeader("Access-Control-Allow-Credentials", "true"); response.setStatus(HttpServletResponse.SC_OK); } else { filterChain.doFilter(request, response); } } ``` ### 总结 在前后端分离架构中,Spring Security 的 CORS 配置是确保前后端正常通信的关键。通过 `WebMvcConfigurer` 配置全局 CORS 策略,并在 `HttpSecurity` 中启用 CORS 支持,可以有效解决跨域请求问题。同时,需要确保 OPTIONS 请求的正确处理,以便浏览能够顺利通过预检请求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值