Spring Security 源码解析 -- 安全认证动态权限之基于内存模式
Spring Security 入门相关概念
Spring Security 是基于Spring IOC框架基础上进行实现的,所以Spring Security在实现安全认证、动态权限上使用了Spring 框架的一些家族语音的注解、特性等等。通过源码发现, 应用Spring Security 功能使用EnableWebSecurity注解即可启用功能, 最终以Filter链的形式来处理认证和权限的。下面就根据EnableWebSecurity注解来一一展开讲解Spring Security相关源码吧,并通过代码形式入门Spring Security的内存模式。
项目依赖包
首先,通过pom.xml文件处理Spring Security的依赖。Spring Cloud系列都是基于spring boot 2.3.3.RELEASE和spring cloud Hoxton.SR8.
在项目中依赖jar包如下:
EnableWebSecurity
在项目中新建WebSecurityConfig类, 继承WebSecurityConfigurerAdapter,并使用EnableWebSecurity就可以开启Spring Security 的安全认证了。
其中EnableWebSecurity注解通过源码只知,其下有三个注解,分别是WebSecurityConfiguration、SpringWebMvcImportSelector、Oauth2ImportSelector三个注解, 其中通过源码分析,SpringWebMvcImportSelector注入了一个WebMvcSecurityConfiguration
WebMvcSecurityConfiguration是用于处理Web请求下增加了Controller上的方法参数解析器,分别添加AuthenticationPrincipalArgumentResolver、CurrentSecurityContextArgumentResolver、CsrfTokenArgumentResolver三个参数解析器,用于处理AuthenticationPrincipal、CurrentSecurityContext两个注解的参数解析,及CsrfToken参数的解析。
OAuth2ImportSelector就不在此处展开讲解了。
WebSecurityConfiguration
WebSecurityConfiguration 是整个Spring Security框架处理的核心, 主要包含了WebSecurity、HttpSecurity及自定义的WebSecurityConfig继承WebSecurityConfigurerAdapter。
通过AutowiredWebSecurityConfigurersIgnoreParents.getWebSecurityConfigurers方法获取到自定义的WebSecurityConfigurer的Bean,用于后续配置WebSecurity和HttpSecurity做准备。
首先new了一个WebSecurity对象,并且获取到上面流程中的自定义的WebSecurityConfigurer,根据Order进行排序。并且不能出现相同排序自定义的WebSecurityConfigurer.
把自定义的WebSecurityConfigurer添加到WebSecurity对象中, 用于后面的build使用。
此方法中最终对WebSecurity进行build,生成Filter过滤器处理Web请求进行过滤拦截处理。
在build过程中,其中最重要的三个方法分别是init 、configure和performBuild
其中init 、 configure方法就是获取到对自定义的WebSecurityConfigurer进行init方法、configure方法调用, 而主要实现的功能都在抽象类WebSecurityConfigurerAdapter中。
WebSecurityConfigurerAdapter已经实现了非常重要的init方法,此方法会获取到HttpSecurity,而HttpSecurity就是用于设置所有Web请求相关的SecurityConfigurer,而这所有的SecurityConfigurer最终在HttpSecurity进行Build的时候会获取到Filter。
HttpSecurity在实例化时,会获取AuthticationManager。
默认获取AuthticationManager时,会从配置类AuthenticationConfiguration中得到。
而Authentication在获取AuthenticationManager时会加载一些默认的配置类数据, 分别是InitializeAuthenticationProviderBeanManagerConfigurer、InitializeUserDetailsBeanManagerConfigurer。
此处会注入一个AuthticationMangerBuilder,并设置事件发布器、密码编码器。
AuthticationBuilder在Build时,会进行上面两个配置类:InitializeAuthenticationProviderBeanManagerConfigurer、InitializeUserDetailsBeanManagerConfigurer中处理init 方法,并处理这两个类生成的内部类的configure方法。
最终以InitializeUserDetailsManagerConfigurer为例,此类会配置一个DaoAuthenticationProvider,此类根据authenticationProvider方法加入到AuthenticationManagerBuilder中的authenticationProviders列表中。
最后在AuthenticationBuilder类中的performBuild方法最终会返回ProviderManager对象,此对象就是管理所有的AuthenticationProvider,并且支持父级的AuthenticationManger对象。其中ProvidernManager是用于管理用户认证的, 实际认证是AuthenticationProvider接口的实现类, 默认是DaoAuthticationProvider进行用户认证。最终DaoAuthticationProvider会根据内存模式还是数据库模式的UserDetailsService进行加载用户数据来协助认证。
从此处可以看到,如果自定义父级AuthenticationManger可以直接覆盖configure(AuthenticationManagerBuilder auth)方法,方法如下所示:
所以基于上面,AuthenticationManger的默认设置就介绍完了,紧接着就是HttpSecurity的一些列的配置。其中AuthticationBuilder就是默认的DefaultPasswordEncoderAuthenticationManagerBuilder,其父级AuthticationBuilder就是上面介绍的默认AuthticationConfiguration配置中获取的,最后configure方法用于配置自定义的HttpSecurity了。
最后基于内存模式就只需要设置到如下即可:
通过localhost:1223/login 就可以登录啦, 但是此登录只是简单的登录,并没有设置登录成功的跳转页面。下一个篇章将介绍基于数据库模式进行登录。