SpringSecurity源码学习(五)
来源:互联网 发布:国外域名商哪个便宜 编辑:程序博客网 时间:2024/06/10 00:30
前言
总结创建HttpSecuirty的创建过程,及其构建SecurityFilterChain过程。有和前面重复的地方,不管了…
触发HttpSecurity的创建过程
前面谈到,WebSecurity构建FilterChainProxy的过程中使用到了WebSecurityConfigurerAdapter的一个子类(这个子类一般需要用户定义的),调用了其init()。正是在这里,触发了HttpSecurity的构建过程。
public void init(final WebSecurity web) throws Exception { //触发了HttpSecurity的构建 final HttpSecurity http = getHttp(); web.addSecurityFilterChainBuilder(http).postBuildAction(new Runnable() { public void run() { FilterSecurityInterceptor securityInterceptor = http .getSharedObject(FilterSecurityInterceptor.class); web.securityInterceptor(securityInterceptor); } }); }
创建HttpSecurity
protected final HttpSecurity getHttp() throws Exception { if (http != null) { return http; } DefaultAuthenticationEventPublisher eventPublisher = objectPostProcessor .postProcess(new DefaultAuthenticationEventPublisher()); /* * localConfigureAuthenticationBldr=“本地的授权管理器构建器”,它是可以由用户配置的 */ localConfigureAuthenticationBldr.authenticationEventPublisher(eventPublisher); /** * 此方法用于创建“授权管理器”,比较重要,下文单独介绍。 * 使用“本地的授权管理器构建器”构建授权管理器 */ AuthenticationManager authenticationManager = authenticationManager(); /** * authenticationBuilder=“默认的的授权管理器”,这个是框架提供的默认配置 * 将使用本地配置构建的授权管理器,作为默认的授权管理器的父管理器 */ authenticationBuilder.parentAuthenticationManager(authenticationManager); /** * 参数一:后置处理器,前面说过很多次了 * 参数二:授权管理器的构建器 * 参数三:HttpSecurity是用于构建真正处理请求的SecurityFilterChian,它使用了很多配置 * 器,这个配置器在创建的过程中可以共享一个对象(比如:ApplicationContext)。 * localConfigureAuthenticationBldr.getSharedObjects()用于获取用户自定义 * 共享对象。 */ http = new HttpSecurity(objectPostProcessor, authenticationBuilder, localConfigureAuthenticationBldr.getSharedObjects()); /** * 设置共享对象。userDetailsService()方法后文详讨论。 */ http.setSharedObject(UserDetailsService.class, userDetailsService()); http.setSharedObject(ApplicationContext.class, context); http.setSharedObject(ContentNegotiationStrategy.class, contentNegotiationStrategy); http.setSharedObject(AuthenticationTrustResolver.class, trustResolver); /** * 默认配置。 * 1)、添加了n多SecurityFilterChian的构建器的配置器 * 2)、直接添加了n多过滤器 * 关于每个配置的作用,将单列一章讨论。 */ if (!disableDefaults) { http .csrf().and() .addFilter(new WebAsyncManagerIntegrationFilter()) .exceptionHandling().and() .headers().and() .sessionManagement().and() .securityContext().and() .requestCache().and() .anonymous().and() .servletApi().and() .apply(new DefaultLoginPageConfigurer<HttpSecurity>()).and() .logout(); } /** * 此方法被用户重写去修改默认配置。 * 比如禁用csrf()、比如添加验证码校验、比如自定义权限认证 */ configure(http); return http; }
使用本地配置构建授权管理器
protected AuthenticationManager authenticationManager() throws Exception { if (!authenticationManagerInitialized) { /** * 这个方法由用户重写 */ configure(localConfigureAuthenticationBldr); /** * 如果用户对configure(AuthenticationManagerBuilder auth)方法进行了重写, * 那么,disableLocalConfigureAuthenticationBldr将为false,即:将使用用户的 * 配置来构建“授权管理器” */ if (disableLocalConfigureAuthenticationBldr) { authenticationManager = authenticationConfiguration .getAuthenticationManager(); } else { authenticationManager = localConfigureAuthenticationBldr.build(); } authenticationManagerInitialized = true; } return authenticationManager; }
创建共享对象UserDetailsService
@EnableWebSecurity这个注解其实也被@EnableGlobalAuthentication注解修饰。它导入了一个关于认证的配置类:AuthenticationConfiguration。这个类中,向容器中创建了AuthenticationManagerBuilder。
@Bean public AuthenticationManagerBuilder authenticationManagerBuilder( ObjectPostProcessor<Object> objectPostProcessor) { return new AuthenticationManagerBuilder(objectPostProcessor); }
为什么这么麻烦的获取UserDetailsService?
protected UserDetailsService userDetailsService() { AuthenticationManagerBuilder globalAuthBuilder = context .getBean(AuthenticationManagerBuilder.class); return new UserDetailsServiceDelegator(Arrays.asList( localConfigureAuthenticationBldr, globalAuthBuilder)); }
其实是SpringSecurity提供了两种设置UserDetailsService的方式
第一种:@EnableWebSecurity@ComponentScan("fn.wd.security")public class SpringSecurityConfiger extends WebSecurityConfigurerAdapter { @Autowired private CustomUserDetailService customUserDetailService; @Autowired private AuthenticationManagerBuilder authenticationManagerBuilder; @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { authenticationManagerBuilder.userDetailsService(customUserDetailService) .passwordEncoder(standardPasswordEncoder()); }}
第二种:@EnableWebSecurity@ComponentScan("fn.wd.security")public class SpringSecurityConfiger extends WebSecurityConfigurerAdapter { @Autowired private CustomUserDetailService customUserDetailService; @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(customUserDetailService) .passwordEncoder(standardPasswordEncoder()); }}
触发HttpSecurity的构建过程
HttpSecurity的构建过程是由WebSecurity构建具体的SecurityFilterChain时触发的:
protected Filter performBuild() throws Exception { int chainSize = ignoredRequests.size() + securityFilterChainBuilders.size(); List<SecurityFilterChain> securityFilterChains = new ArrayList<SecurityFilterChain>( chainSize); for (RequestMatcher ignoredRequest : ignoredRequests) { securityFilterChains.add(new DefaultSecurityFilterChain(ignoredRequest)); } for (SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder : securityFilterChainBuilders) { //securityFilterChainBuilder.build()触发构建过程 securityFilterChains.add(securityFilterChainBuilder.build()); } FilterChainProxy filterChainProxy = new FilterChainProxy(securityFilterChains); if (httpFirewall != null) { filterChainProxy.setFirewall(httpFirewall); } filterChainProxy.afterPropertiesSet(); Filter result = filterChainProxy; postBuildAction.run(); return result; }
定义构建的模版
不要忘记HttpSecurity和WebSecurity一样,都是AbstractConfiguredSecurityBuilder的子类。AbstractConfiguredSecurityBuilder中定义了构建的模版:
@Override protected final O doBuild() throws Exception { synchronized (configurers) { buildState = BuildState.INITIALIZING; beforeInit(); init();//调用所有配置器的init() buildState = BuildState.CONFIGURING; beforeConfigure(); configure();//调用所有配置器的configurer() buildState = BuildState.BUILDING; O result = performBuild();//最后调用HttpSecurity中performBuild的实现 buildState = BuildState.BUILT; return result; } }
构建SecurityFilterChain
由于这个构建器(HttpSecurity)里面的构建器配置器很多,所以init()、configurer()会比较复杂,后面详讨论吧,这里重点看下HttpSecurity的performBuild():
@Override protected DefaultSecurityFilterChain performBuild() throws Exception { //comparator其实就是FilterComparator的对象 Collections.sort(filters, comparator); return new DefaultSecurityFilterChain(requestMatcher, filters); }
可以看到的是,HttpSecurity只是将配置器配置的结果(filters)按照某种规则(FilterComparator)排序。
FilterComparator内部其实已经定义了框架提供的过滤器的顺序。当我们向过滤器链中插入一个过滤器(比如:插入校验验证码的过滤器)时,不仅是将此过滤器添加到HttpSecurity的配置中,还修改了这个比较器。比如HttpSecurity的addFilterBefore()方法:
public HttpSecurity addFilterBefore(Filter filter, Class<? extends Filter> beforeFilter) { //先修改比较器 comparator.registerBefore(filter.getClass(), beforeFilter); //然后才添加到配置中 return addFilter(filter); }
- SpringSecurity源码学习(五)
- SpringSecurity源码学习(一)
- SpringSecurity源码学习(二)
- SpringSecurity源码学习(三)
- SpringSecurity源码学习(六)
- SpringSecurity(五):RememberMe以及源码分析
- springsecurity学习(一)
- SpringSecurity学习(一)
- SpringSecurity 源码解读(一)
- SpringSecurity学习笔记之五:认证用户
- SpringSecurity 学习记录(一)- SpringSecurity 主要的实现类
- SpringSecurity源码解读(二) successHandler
- SpringBoot学习(六)SpringSecurity学习
- Atlas源码学习(五)
- nginx源码学习(五)
- SpringSecurity | spring security oauth2.0 配置源码分析(一)
- Spring+SpringSecurity 学习总结
- SpringSecurity学习笔记一
- $.ajax()方法详解
- Oracle RAC SCAN NAME域名解析服务精简版配置
- (笔记)封装好的连接数据库方法,避免多次连接数据库
- 离职流程
- sql操作的部分优化
- SpringSecurity源码学习(五)
- 蓝桥杯ADV-101——算法提高 断案
- hive union
- Spring Quartz 多任务、并发配置
- Java面向对象之继承
- 理解对象模型OMD(课堂笔记)
- poj 2492 A Bug's Life(并查集 染色法 二分图)
- 判断线面相交问题
- 4. Median of Two Sorted Arrays