1.常规pom导入
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
2.部分源码分析
学习是来自于SpringSecurity源码分析(一) SpringBoot集成SpringSecurity即Spring安全框架的加载过程_spring security源码-CSDN博客
2.1 springsecurity入口
springsecurity的pom导入之后其实其实是加载SecurityAutoConfiguration这个类,你可以把它看成是一个入口,重点是红色标注这两个
2.1.1 默认加载
SpringBootWebSecurityConfiguration这个类是在加载springsecurity时,判断是你是否有自己继承了一个WebSecurityConfigurerAdapter的东西,也是我认为是springsecurity的一个核心。如果没有它就会加载一个默认的DefaultConfigurerAdapter
2.1.2 具体的加载过程
2.1.2.1 开始
为什么需要这个adapter呢,我们继续最开始圈起来的第二个类WebSecurityEnablerConfiguration,点完之后继续点击注解@EnableWebSecurity,找到import 的这个类WebSecurityConfiguration
在这个类里面,debug一下会发现这个是一个hasConfigurers=true,所以中间代码不执行,但是webSecurity 这个类会自动加载,也是在这个类下面@Autowired 自动执行的这段代码,本质就是创建一个websecurity,然后就可以执行我们上面圈起来的buid()方法了
然后build的过程比较复杂,源码比较多,但是本质都是通过build()来拿到不同的providerManager对象,其中websecurity.build 是最外层,在build的过程中还有两个比较重要的类,来调用build(),分别是
2.1.2.2 httpsecuirty.build()
其中http在build()的过程中通过configure()方法完成了filter的加载。
2.1.2.3 AuthenticationManagerBuilder.build()
这个build的过程主要是给providerManager 的provder赋值,例如:我们如果实现了UserDetailService 的类的加载,passwordEncode类的加载。这些都需要被spring管理才能放到provider中。如果没有实现会有默认
AuthenticationProvider authenticationProvider = getBeanOrNull( AuthenticationProvider.class);
关于这个构建的过程我就画了个图,方便大家一起理解
做一些简单的更新:
在websecurity.build()的时候, 里面会先init(),这个过程中会拿到所有继承了WebSecurityConfigurerAdapter这个类的子类,并且执行这个玩意的init()方法。当然你也可以在初始化过程中写一些你想提前加载的东西(我暂时不知道是干啥的,但是是这样的流程)
这个init()中会执行一个getHttp()方法,这个方法就是获取一个叫httpSecurity的类。当然这个方法还干了一个事,就是执行authenticationManager()方法。
这个方法呢,是AuthenticationManagerBuilder.build()方法拿到一个providerManage类放到websecurity构建的providerManager中
2.1.3 过滤器顺序
这里的过滤器其实是排好序的,通过Collections.sort(filters, comparator);这个玩意排序的,但是我没有看懂。大家有懂得可以说一下,在具体的过滤器中也没有找到order这种标识
2.1.3.1 UsernamePasswordAuthenticationFilter
这个过滤器主要看attemptAuthentication()这个方法。因为他的父类实现了dofilter(),并在其中调用了这个抽象方法,所有子类看这个实现就完事
this.getAuthenticationManager().authenticate(authRequest) 这个玩意就是去对比或者叫认证你的账号密码的。前半截返回的都是providerManager,我们之前的build的返回结果就是这个玩意,这个地方就用到了
在后半截,会拿出来DaoAuthenticationProvider.authenticate()。这个方法是在父类AbstractUserDetailsAuthenticationProvider中写的。你需要到父类中去看,里面重点就是这段代码
user = retrieveUser(username, (UsernamePasswordAuthenticationToken) authentication)
UserDetails loadedUser = this.getUserDetailsService().loadUserByUsername(username);
this.getUserDetailsService() ,如果有自己有实现了UserDetailsService,并且别spring管理,那么这个地方加载的是你的实现。如果没有就是默认的InMemoryUserDetailsManager。这个就是我们在2.1.2.3提到的初始化加载。然后调用loadUserByUsername就是对比账号密码了