写点什么

Spring Boot 集成 Spring Security 之自动装配

  • 2024-10-12
    福建
  • 本文字数:5479 字

    阅读完需:约 18 分钟

实现功能及软件版本说明


  1. 使用 Spring Boot 集成 Spring Security 实现 Servlet 项目的安全个性化配置

  2. Spring Boot 版本:2.7.18

  3. Spring Security 版本:5.7.11


创建 Spring Boot 项目


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



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 相关自动装配配置类



自动装配配置类之 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 容器中注入默认过滤器链,即用户没有自定义过滤器链时,生成默认过滤器链



2、Spring 容器中不存在名称为 springSecurityFilterChain 对象时,启用 WebSecurity,即用户未显示的启用 WebSecurity 时,隐式的启用 WebSecurity



4、@EnableWebSecurity


1)、部分源码


@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)@Documented@Import({ WebSecurityConfiguration.class, SpringWebMvcImportSelector.class, OAuth2ImportSelector.class,		HttpSecurityConfiguration.class })@EnableGlobalAuthentication@Configurationpublic @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<>();	}
复制代码


3、通过配置文件可以修改默认用户名、密码、角色(示例如下)



自动装配配置类之 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


文章转载自:那你为何对我三笑留情

原文链接:https://www.cnblogs.com/sanxiaolq/p/18458562

体验地址:http://www.jnpfsoft.com/?from=infoq

用户头像

还未添加个人签名 2023-06-19 加入

还未添加个人简介

评论

发布
暂无评论
Spring Boot集成Spring Security之自动装配_spring_快乐非自愿限量之名_InfoQ写作社区