关于Spring Security的过滤器分析,在kirito的https://mp.weixin.qq.com/s?__biz=MzUzNTY4NTYxMA==&mid=2247484293&idx=2&sn=62ca751be311ba6ddcdf2790bd0c4ac6&chksm=fa80f300cdf77a16c7f0e38200dcc3fe8010bbc6586e43775c7b1be97732eabd1c3b7d1581c3&scene=21#wechat_redirect 分析中已经说得很清楚,但是我很好奇为什么在请求中鉴权失败时候生成的匿名用户他的权限会是ROLE_ANONYMOUS,之前一直看过很多关于为什么要看源码的文章,总结下来就是可以通过看优秀的源码我们可以学习到开发者各种优秀的开发模式的结合,还有他们优美的代码,另外一方面我们可以通过阅读源码了解其运作的方式,为我们使用框架和日后的修改提供支撑。下面是我如何通过IDEA去寻答案。
1.巧用IDEA内置功能
在我上一篇文章工欲善其事,必先利其器-IntelliJ IDEA中简单介绍IDEA,而IDEA又一个功能可以方便我们去了解代码中相互的调用关系。
设置寻找文件的作用域原来的设置是寻找当前我们写的Project Files中,我们要设置系统寻找的作用域为Project and Libraries
使用右键的Find Usages寻找调用类
2.AnonymousAuthenticationFilter初始化时序图
通过Usages对调用类的定位,还有使用DEBUGGER模式,我们可以大概得到这样的时序图,可以看出在最后的几步才对AnonymousAuthenticationFilter进行初始化,并且加入到过滤器链路。
3.主要代码说明
HttpSecurity
HttpSecurity的doBuild中会依次地执行init()对AnonymousAuthenticationFilter进行初始化,configure()加载AnonymousAuthenticationFilter
protected final O doBuild() throws Exception {
synchronized (configurers) {
buildState = BuildState.INITIALIZING;
beforeInit();
init();
buildState = BuildState.CONFIGURING;
beforeConfigure();
configure();
buildState = BuildState.BUILDING;
O result = performBuild();
buildState = BuildState.BUILT;
return result;
}
}
private void init() throws Exception {
Collection<SecurityConfigurer<O, B>> configurers = getConfigurers();
for (SecurityConfigurer<O, B> configurer : configurers) {
configurer.init((B) this);
}
for (SecurityConfigurer<O, B> configurer : configurersAddedInInitializing) {
configurer.init((B) this);
}
}
private void configure() throws Exception {
Collection<SecurityConfigurer<O, B>> configurers = getConfigurers();
for (SecurityConfigurer<O, B> configurer : configurers) {
configurer.configure((B) this);
}
}
AnonymousConfigurer
HttpSecurity的在执行init()时,会依次执行Collection<SecurityConfigurer<O, B>> configurers的init(),当对AnonymousConfigurer进行初始化的时候,对authenticationFilter = new AnonymousAuthenticationFilter(getKey(), principal,authorities);的时候因为authorities在类定义的时候初始化已经拥有了ROLE_ANONYMOUS的权限,所以在默认初始化的过滤器的时候就会带有ROLE_ANONYMOUS的权限,并且当HttpSecurity在configure()依次执行到AnonymousConfigurer的configure()时候就会把初始后的authenticationFilter加载到过滤链路中。
public final class AnonymousConfigurer<H extends HttpSecurityBuilder<H>> extends
AbstractHttpConfigurer<AnonymousConfigurer<H>, H> {
private String key;
private AuthenticationProvider authenticationProvider;
private AnonymousAuthenticationFilter authenticationFilter;
private Object principal = "anonymousUser";
private List<GrantedAuthority> authorities = AuthorityUtils
.createAuthorityList("ROLE_ANONYMOUS");
public void init(H http) throws Exception {
if (authenticationProvider == null) {
authenticationProvider = new AnonymousAuthenticationProvider(getKey());
}
if (authenticationFilter == null) {
authenticationFilter = new AnonymousAuthenticationFilter(getKey(), principal,
authorities);
}
authenticationProvider = postProcess(authenticationProvider);
http.authenticationProvider(authenticationProvider);
}
public void configure(H http) throws Exception {
authenticationFilter.afterPropertiesSet();
http.addFilter(authenticationFilter);
}
}
总结
源码的研究可以让我们自己更加了解对应的框架,后面会通过解读源码和修改源码来实现我们在实际使用Srping Security时候的需求。