Spring Security默认用户生成分析

1.首先创建进行环境搭建

  • 创建SpringBoot项目
  • 引入SpringSecurity依赖
  • 编写简单的Controller

Spring Security默认用户生成分析_第1张图片

2.使用断点进行源码查看

①首先访问资源localhost:8080/hello

之后会被/login页面拦截,在/login页面拦截之后输入用户密码,会被formLogin()方法进行捕获(根据类SpringBootWebSecurityConfiguration显示

Spring Security默认用户生成分析_第2张图片

查看该方法,发现该方法应用了FormLoginConfigurer的实现,进入该类

在这里插入图片描述

②查看FormLoginConfigurer类

该类中调用了父类的UsernamePasswordAuthenticationFilter,因此肯定会被此Filter捕获到,会进入到该类中。

Spring Security默认用户生成分析_第3张图片

因此在该类中attempAuthentication方法处打断点,发送请求,点击登录之后,会进入到此处,可以发现最后返回的是authencicate方法,并且将验证请求信息传了进去,进入该方法查看。

③查看UsernamePasswordAuthenticationFilter类

Spring Security默认用户生成分析_第4张图片

④查看ProviderManager的authenticate方法

Spring Security默认用户生成分析_第5张图片

AuthenticationManager会调用providerManager,providerManager提供者会有很多种认证方式,如果返回一个完整的Authenticate,则代表认证成功。

根据源代码发现,authenticate会回调父类中的authenticate方法。由于父类中的AuthenticationManager是一个接口,因此接口的实现类只能靠子类,因此,他回调的时候是回调了他自己的authenticate的方法。

Spring Security默认用户生成分析_第6张图片

ProviderManager的父接口是AuthenticationManager

在这里插入图片描述

AuthenticationManager是一个接口。

在这里插入图片描述

再次进入到authentication方法,认证是通过providerManager不断的循环,直到能够找到能够认证通过的就认证成功,如果没有找到,那么就认证失败。

Spring Security默认用户生成分析_第7张图片

在这个回调之后,可以发现,终于有了自己的实现,进入该方法内。

Spring Security默认用户生成分析_第8张图片

⑤查看AbstractUserDetailsAuthenticationProvider类中的authenticate方法

进入该方法后,可以发现,这次并不是ProviderManager类中的方法了,而是AbstractUserDetailsAuthenticationProvider类中的方法,也就是说AbstractUserDetailsAuthenticationProvider类是ProviderManager类的实现类,他也实现了这个authenticate方法。该方法中调用了determineUsername方法,去判断当前身份是否为空,如果为空,则返回NONE_PROVIDED,如果不为空,则返回用户名。说明该方法并不是完成认证的方法。

Spring Security默认用户生成分析_第9张图片

determineUsername方法

在这里插入图片描述

retrieveUser是真正做认证的方法,因此进入该方法中进行查看。

Spring Security默认用户生成分析_第10张图片

⑥进入DaoAuthenticationProvider中的retrieveUser

retrieveUser中,可以看到该语句

Spring Security默认用户生成分析_第11张图片

UserDetails loadedUser = this.getUserDetailsService().loadUserByUsername(username);

说明他会拿着用户输入的用户名去UserDetailsService中的loadUserByUsername方法,因此只需要查看loadUserByUsername的具体实现即可。

查看 this.getUserDetailsService()的实现,可以发现他的结果是一个InMemoryUserDetailsManager,说明是基于内存的实现。

因此认证时所需要的数据源是Spring Security基于内存的实现。

⑦查看getUserDetailsService实现类。

Spring Security默认用户生成分析_第12张图片

UserDetailService

Spring Security默认用户生成分析_第13张图片

public interface UserDetailsService {

	UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;

}

Spring Security默认用户生成分析_第14张图片

UserDetailService是顶层父接口,接口中loadUserByUserName方法是用来在用户认证时进行用户名认证方法,默认实现使用内存实现,如果想要修改数据库实现,只需要自定义UserDetailService实现,最终返回UserDetails实例即可。

⑧查看InMemoryUserDetailsManager中的loadUserByUserName

由UserDetailsManager的类可以发现,InMemoryUserDetailsManager类会对loadUserByUserName方法进行实现,查看该类

Spring Security默认用户生成分析_第15张图片

该方法对本类中的users进行获取,之后返回一个完整的users对象。

在这里插入图片描述

由于UserDetailsService默认是基于内存的配置,因此查看他的自动配置信息。

⑨UserDetailServiceAutoConfiguration

这个类的源码非常多,关键部分:

//该类生效条件
@Configuration(proxyBeanMethods = false)
//当类路径下存在AuthenticationManager.class时,默认引入Spring Security即会存在。
@ConditionalOnClass(AuthenticationManager.class)
//当类中存在ObjectPostProcessor.class时,该类为Spring容器中存在。
@ConditionalOnBean(ObjectPostProcessor.class)
//当前工程中没有自定义AuthenticationManager.class, AuthenticationProvider.class, UserDetailsService.class,
//				AuthenticationManagerResolver.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" })
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());
	}

	// ...

}

默认情况下该类中的条件都能够满足,此时Spring Security会提供一个InMemoryUserDetailManager实例。

Spring Security默认用户生成分析_第16张图片

说明User是SecurityProperties的静态内部类,查看getUser方法,可以发现返回一个User,查看User。

在这里插入图片描述

该静态内部类中初始化了一个username为:user。

password为UUID随机生成的。

Spring Security默认用户生成分析_第17张图片

发现该类中出现@ConfigurationProperties注解,给属性注入,因此以后可以在配置文件中修改默认的username,password以及roles。

在这里插入图片描述
Spring Security默认用户生成分析_第18张图片

你可能感兴趣的:(SpringSecurity,spring,java,Spring,Security)