二、实现功能及软件版本说明
- 使用Spring Boot集成Spring Security实现Servlet项目的安全个性化配置
- Spring Boot版本:2.7.18
- Spring Security版本:5.7.11
三、创建Spring Boot项目
- 创建Spring Boot项目,目次结构如下
- 引入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、紧张作用
- 导入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)、紧张作用
- 默认Security配置(Spring容器中没有SecurityFilterChain和WebSecurityConfigurerAdapter)时,向Spring容器中注入默认过滤器链,即用户没有自界说过滤器链时,生成默认过滤器链
- 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
- @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)、紧张作用
- 导入WebSecurityConfiguration
- 导入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)、紧张作用
- 两种方式注册过滤器链:
- 继承WebSecurityConfigurerAdapter(本质是实现SecurityConfigurer接口) (已弃用)
- 直接向Spring容器中注册SecurityFilterChain对象
- 没有默认的过滤器链时,使用WebSecurityConfigurerAdapter中默认配置生成过滤器链
- 根据配置的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)、紧张作用
- Spring容器中注册HttpSecurity对象
- 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、紧张作用
- 用户未自界说认证接口时,生成默认认证接口inMemoryUserDetailsManager(基于内存用户认证)
- 生成默认名称为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<>();
- }
复制代码
- 通过配置文件可以修改默认用户名、密码、角色(示例如下)
七、自动装配配置类之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、紧张作用
- 注册DelegatingFilterProxyRegistrationBean(委托过滤器代理注册Bean)
- 设置代理目标Bean对象名称为springSecurityFilterChain
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |