一、Spring Boot集成Spring Security之自动装配

二、实现功能及软件版本说明

  1. 使用Spring Boot集成Spring Security实现Servlet项目的安全个性化配置
  2. Spring Boot版本:2.7.18
  3. Spring Security版本:5.7.11

三、创建Spring Boot项目

  1. 创建Spring Boot项目,目录结构如下

    一、Spring Boot集成Spring Security之自动装配

  2. 引入Spring Security包,完整pom.xml如下

<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">     <modelVersion>4.0.0</modelVersion>      <parent>         <groupId>org.springframework.boot</groupId>         <artifactId>spring-boot-starter-parent</artifactId>         <version>2.7.18</version>         <relativePath/>     </parent>      <groupId>com.yu</groupId>     <artifactId>spring-boot-security2-demo</artifactId>     <version>0.0.1-SNAPSHOT</version>     <name>spring-boot-security2-demo</name>     <description>Spring Boot集成Spring Security样例</description>      <properties>         <java.version>8</java.version>     </properties>      <dependencies>         <dependency>             <groupId>org.springframework.boot</groupId>             <artifactId>spring-boot-starter-web</artifactId>         </dependency>         <dependency>             <groupId>org.springframework.boot</groupId>             <artifactId>spring-boot-starter-security</artifactId>         </dependency>     </dependencies>  </project>  

四、查看自动装配配置类

  • 查看Security Servlet相关自动装配配置类

    一、Spring Boot集成Spring Security之自动装配

五、自动装配配置类之SecurityAutoConfiguration

1、部分源码

@AutoConfiguration @ConditionalOnClass(DefaultAuthenticationEventPublisher.class) @EnableConfigurationProperties(SecurityProperties.class) @Import({ SpringBootWebSecurityConfiguration.class, SecurityDataConfiguration.class }) public class SecurityAutoConfiguration {  	@Bean 	@ConditionalOnMissingBean(AuthenticationEventPublisher.class) 	public DefaultAuthenticationEventPublisher authenticationEventPublisher(ApplicationEventPublisher publisher) { 		return new DefaultAuthenticationEventPublisher(publisher); 	}  }  

2、主要作用

  1. 导入SpringBootWebSecurityConfiguration

3、SpringBootWebSecurityConfiguration

1)、部分源码

@Configuration(proxyBeanMethods = false) @ConditionalOnWebApplication(type = Type.SERVLET) class SpringBootWebSecurityConfiguration {  	@Configuration(proxyBeanMethods = false) 	@ConditionalOnDefaultWebSecurity 	static class SecurityFilterChainConfiguration {  		@Bean 		@Order(SecurityProperties.BASIC_AUTH_ORDER) 		SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception { 			http.authorizeRequests().anyRequest().authenticated(); 			http.formLogin(); 			http.httpBasic(); 			return http.build(); 		}  	}  	@Configuration(proxyBeanMethods = false) 	@ConditionalOnMissingBean(name = BeanIds.SPRING_SECURITY_FILTER_CHAIN) 	@ConditionalOnClass(EnableWebSecurity.class) 	@EnableWebSecurity 	static class WebSecurityEnablerConfiguration {  	}  } 

2)、主要作用

  1. 默认Security配置(Spring容器中没有SecurityFilterChain和WebSecurityConfigurerAdapter)时,向Spring容器中注入默认过滤器链,即用户没有自定义过滤器链时,生成默认过滤器链
    一、Spring Boot集成Spring Security之自动装配
  2. Spring容器中不存在名称为springSecurityFilterChain对象时,启用WebSecurity,即用户未显示的启用WebSecurity时,隐式的启用WebSecurity

一、Spring Boot集成Spring Security之自动装配

4、@EnableWebSecurity

1)、部分源码

@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @Documented @Import({ WebSecurityConfiguration.class, SpringWebMvcImportSelector.class, OAuth2ImportSelector.class, 		HttpSecurityConfiguration.class }) @EnableGlobalAuthentication @Configuration public @interface EnableWebSecurity {  	/** 	 * Controls debugging support for Spring Security. Default is false. 	 * @return if true, enables debug support with Spring Security 	 */ 	boolean debug() default false;  } 

2)、主要作用

  1. 导入WebSecurityConfiguration
  2. 导入HttpSecurityConfiguration

5、WebSecurityConfiguration

1)、部分源码

@Configuration(proxyBeanMethods = false) public class WebSecurityConfiguration implements ImportAware, BeanClassLoaderAware { @Bean(name = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME) 	public Filter springSecurityFilterChain() throws Exception { 		boolean hasConfigurers = this.webSecurityConfigurers != null && !this.webSecurityConfigurers.isEmpty(); 		boolean hasFilterChain = !this.securityFilterChains.isEmpty(); 		Assert.state(!(hasConfigurers && hasFilterChain), 				"Found WebSecurityConfigurerAdapter as well as SecurityFilterChain. Please select just one."); 		if (!hasConfigurers && !hasFilterChain) { 			WebSecurityConfigurerAdapter adapter = this.objectObjectPostProcessor 					.postProcess(new WebSecurityConfigurerAdapter() { 					}); 			this.webSecurity.apply(adapter); 		} 		for (SecurityFilterChain securityFilterChain : this.securityFilterChains) { 			this.webSecurity.addSecurityFilterChainBuilder(() -> securityFilterChain); 			for (Filter filter : securityFilterChain.getFilters()) { 				if (filter instanceof FilterSecurityInterceptor) { 					this.webSecurity.securityInterceptor((FilterSecurityInterceptor) filter); 					break; 				} 			} 		} 		for (WebSecurityCustomizer customizer : this.webSecurityCustomizers) { 			customizer.customize(this.webSecurity); 		} 		return this.webSecurity.build(); 	} } 

2)、主要作用

  1. 两种方式注册过滤器链:
    • 继承WebSecurityConfigurerAdapter(本质是实现SecurityConfigurer接口) (已弃用)
    • 直接向Spring容器中注册SecurityFilterChain对象
  2. 没有默认的过滤器链时,使用WebSecurityConfigurerAdapter中默认配置生成过滤器链
  3. 根据配置的SecurityFilterChain集合构建FilterChainProxy类型的对象并注入到Spring容器中名称为springSecurityFilterChain

6、HttpSecurityConfiguration

1)、部分源码

@Configuration(proxyBeanMethods = false) class HttpSecurityConfiguration {  	@Bean(HTTPSECURITY_BEAN_NAME) 	@Scope("prototype") 	HttpSecurity httpSecurity() throws Exception { 		WebSecurityConfigurerAdapter.LazyPasswordEncoder passwordEncoder = new WebSecurityConfigurerAdapter.LazyPasswordEncoder( 				this.context); 		AuthenticationManagerBuilder authenticationBuilder = new WebSecurityConfigurerAdapter.DefaultPasswordEncoderAuthenticationManagerBuilder( 				this.objectPostProcessor, passwordEncoder); 		authenticationBuilder.parentAuthenticationManager(authenticationManager()); 		authenticationBuilder.authenticationEventPublisher(getAuthenticationEventPublisher()); 		HttpSecurity http = new HttpSecurity(this.objectPostProcessor, authenticationBuilder, createSharedObjects()); 		// @formatter:off 		http 			.csrf(withDefaults()) 			.addFilter(new WebAsyncManagerIntegrationFilter()) 			.exceptionHandling(withDefaults()) 			.headers(withDefaults()) 			.sessionManagement(withDefaults()) 			.securityContext(withDefaults()) 			.requestCache(withDefaults()) 			.anonymous(withDefaults()) 			.servletApi(withDefaults()) 			.apply(new DefaultLoginPageConfigurer<>()); 		http.logout(withDefaults()); 		// @formatter:on 		applyDefaultConfigurers(http); 		return http; 	} } 

2)、主要作用

  1. Spring容器中注册HttpSecurity对象
  2. httpSecurity用于配置构建自定义过滤器链

六、自动装配配置类之UserDetailsServiceAutoConfiguration

1、部分源码

@AutoConfiguration @ConditionalOnClass(AuthenticationManager.class) @ConditionalOnBean(ObjectPostProcessor.class) @ConditionalOnMissingBean( 		value = { AuthenticationManager.class, AuthenticationProvider.class, UserDetailsService.class, 				AuthenticationManagerResolver.class }, 		type = { "org.springframework.security.oauth2.jwt.JwtDecoder", 				"org.springframework.security.oauth2.server.resource.introspection.OpaqueTokenIntrospector", 				"org.springframework.security.oauth2.client.registration.ClientRegistrationRepository", 				"org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository" }) public class UserDetailsServiceAutoConfiguration { 	@Bean 	@Lazy 	public InMemoryUserDetailsManager inMemoryUserDetailsManager(SecurityProperties properties, 			ObjectProvider<PasswordEncoder> passwordEncoder) { 		SecurityProperties.User user = properties.getUser(); 		List<String> roles = user.getRoles(); 		return new InMemoryUserDetailsManager(User.withUsername(user.getName()) 			.password(getOrDeducePassword(user, passwordEncoder.getIfAvailable())) 			.roles(StringUtils.toStringArray(roles)) 			.build()); 	} 	private String getOrDeducePassword(SecurityProperties.User user, PasswordEncoder encoder) { 		String password = user.getPassword(); 		if (user.isPasswordGenerated()) { 			logger.warn(String.format( 					"%n%nUsing generated security password: %s%n%nThis generated password is for development use only. " 							+ "Your security configuration must be updated before running your application in " 							+ "production.%n", 					user.getPassword())); 		} 		if (encoder != null || PASSWORD_ALGORITHM_PATTERN.matcher(password).matches()) { 			return password; 		} 		return NOOP_PASSWORD_PREFIX + password; 	} 

2、主要作用

  1. 用户未自定义认证接口时,生成默认认证接口inMemoryUserDetailsManager(基于内存用户认证)
  2. 生成默认名称为user,密码为随机生成的uuid(项目启动时会打印在控制台中),角色为空的用户存入内存中
#UserDetailsServiceAutoConfiguration.inMemoryUserDetailsManager方法中获取user对象 SecurityProperties.User user = properties.getUser(); #SecurityProperties中的User类 public static class User { 		private String name = "user"; 		private String password = UUID.randomUUID().toString(); 		private List<String> roles = new ArrayList<>(); 	} 
  1. 通过配置文件可以修改默认用户名、密码、角色(示例如下)

一、Spring Boot集成Spring Security之自动装配

七、自动装配配置类之SecurityFilterAutoConfiguration

1、部分源码

@AutoConfiguration(after = SecurityAutoConfiguration.class) @ConditionalOnWebApplication(type = Type.SERVLET) @EnableConfigurationProperties(SecurityProperties.class) @ConditionalOnClass({ AbstractSecurityWebApplicationInitializer.class, SessionCreationPolicy.class }) public class SecurityFilterAutoConfiguration {  	private static final String DEFAULT_FILTER_NAME = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME;  	@Bean 	@ConditionalOnBean(name = DEFAULT_FILTER_NAME) 	public DelegatingFilterProxyRegistrationBean securityFilterChainRegistration( 			SecurityProperties securityProperties) { 		DelegatingFilterProxyRegistrationBean registration = new DelegatingFilterProxyRegistrationBean( 				DEFAULT_FILTER_NAME); 		registration.setOrder(securityProperties.getFilter().getOrder()); 		registration.setDispatcherTypes(getDispatcherTypes(securityProperties)); 		return registration; 	}  	private EnumSet<DispatcherType> getDispatcherTypes(SecurityProperties securityProperties) { 		if (securityProperties.getFilter().getDispatcherTypes() == null) { 			return null; 		} 		return securityProperties.getFilter() 			.getDispatcherTypes() 			.stream() 			.map((type) -> DispatcherType.valueOf(type.name())) 			.collect(Collectors.toCollection(() -> EnumSet.noneOf(DispatcherType.class))); 	}  }  

2、主要作用

  1. 注册DelegatingFilterProxyRegistrationBean(委托过滤器代理注册Bean)
  2. 设置代理目标Bean对象名称为springSecurityFilterChain
发表评论

相关文章