文章目录

  • 一、WebSecurityConfigurerAdapter是什么?
    • 1.WebSecurityConfigurer是什么?
    • 2.WebSecurity
      • 2.1 WebSecurity定义
      • 2.2 AbstractConfiguredSecurityBuilder
      • 2.3 再次看WebSecurity
    • 3 WebSecurityConfigurerAdapter

一、WebSecurityConfigurerAdapter是什么?

WebSecurityConfigurerAdapter是为创建WebSecurityConfigurer实例提供方便的基类,该类允许开发人员通过覆盖方法进行定制。
类图:

通过类图,可以了解到WebSecurityConfigurerAdapter实现了WebSecurityConfigurer的接口。

1.WebSecurityConfigurer是什么?

public interface WebSecurityConfigurer<T extends SecurityBuilder<Filter>> extends SecurityConfigurer<Filter, T> {}

WebSecurityConfigurer是一个空的接口,它允许对WebSecurity进行定义,目的就是配置一个WebSecurity。

2.WebSecurity

2.1 WebSecurity定义

public final class WebSecurity extends AbstractConfiguredSecurityBuilder<Filter, WebSecurity>implements SecurityBuilder<Filter>, ApplicationContextAware {

可以看到WebSecurity继承了AbstractConfiguredSecurityBuilder并实现了SecurityBuilder。
之前分析了解到,WebSecurity由WebSecurityConfiguration创建,以创建称为 Spring Security Filter Chain (springSecurityFilterChain) 的FilterChainProxy 。

2.2 AbstractConfiguredSecurityBuilder

AbstractConfiguredSecurityBuilder维护了每一个子类的实现集合,例如我们探讨的WebSecurity,当我们定义了多个WebSecurityConfigurerAdapter时,会在全局变量configurers属性中维护具体配置。
维护源码:

 private <C extends SecurityConfigurer<O, B>> void add(C configurer) {Assert.notNull(configurer, "configurer cannot be null");Class<? extends SecurityConfigurer<O, B>> clazz = (Class<? extends SecurityConfigurer<O, B>>) configurer.getClass();synchronized (this.configurers) {if (this.buildState.isConfigured()) {throw new IllegalStateException("Cannot apply " + configurer + " to already built object");}List<SecurityConfigurer<O, B>> configs = null;if (this.allowConfigurersOfSameType) {configs = this.configurers.get(clazz);}configs = (configs != null) ? configs : new ArrayList<>(1);configs.add(configurer);this.configurers.put(clazz, configs);if (this.buildState.isInitializing()) {this.configurersAddedInInitializing.add(configurer);}}}public <C extends SecurityConfigurer<O, B>> List<C> getConfigurers(Class<C> clazz) {List<C> configs = (List<C>) this.configurers.get(clazz);if (configs == null) {return new ArrayList<>();}return new ArrayList<>(configs);}
  1. add()方法将传入的configer维护到了configers里,configurers 本身是一个 LinkedHashMap ,key 是配置类的 class,value 是一个集合,集合里边放着 xxxConfigure 配置类。
  2. 当需要对这些配置类进行集中配置的时候,会通过 getConfigurers 方法获取配置类,这个获取过程就是把 LinkedHashMap 中的 value 拿出来,放到一个集合中返回。

AbstractConfiguredSecurityBuilder中还有一个特别重要的方法就是doBuild方法。

 @Overrideprotected final O doBuild() throws Exception {synchronized (this.configurers) {this.buildState = BuildState.INITIALIZING;beforeInit();init();this.buildState = BuildState.CONFIGURING;beforeConfigure();configure();this.buildState = BuildState.BUILDING;O result = performBuild();this.buildState = BuildState.BUILT;return result;}}private void configure() throws Exception {Collection<SecurityConfigurer<O, B>> configurers = getConfigurers();for (SecurityConfigurer<O, B> configurer : configurers) {configurer.configure((B) this);}}

doBuild方法的入口是自动配置WebSecurityConfiguration的springSecurityFilterChain方法:

@Bean(name = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)public Filter springSecurityFilterChain() throws Exception {boolean hasConfigurers = this.webSecurityConfigurers != null && !this.webSecurityConfigurers.isEmpty();boolean hasFilterChain = !this.securityFilterChains.isEmpty();Assert.state(!(hasConfigurers && hasFilterChain),"Found WebSecurityConfigurerAdapter as well as SecurityFilterChain. Please select just one.");if (!hasConfigurers && !hasFilterChain) {WebSecurityConfigurerAdapter adapter = this.objectObjectPostProcessor.postProcess(new WebSecurityConfigurerAdapter() {});this.webSecurity.apply(adapter);}for (SecurityFilterChain securityFilterChain : this.securityFilterChains) {this.webSecurity.addSecurityFilterChainBuilder(() -> securityFilterChain);for (Filter filter : securityFilterChain.getFilters()) {if (filter instanceof FilterSecurityInterceptor) {this.webSecurity.securityInterceptor((FilterSecurityInterceptor) filter);break;}}}for (WebSecurityCustomizer customizer : this.webSecurityCustomizers) {customizer.customize(this.webSecurity);}return this.webSecurity.build();}

此处调用build方法,最终调用的是duBuild方法。
doBuild 方法就是一边更新状态,进行进行初始化。
beforeInit 是一个预留方法,没有任何实现。
init 方法就是找到所有的 xxxConfigure,挨个调用其 init 方法进行初始化。
beforeConfigure 是一个预留方法,没有任何实现。
configure 方法就是找到所有的 xxxConfigure,挨个调用其 configure 方法进行配置。
最后则是 performBuild 方法,是真正的过滤器链构建方法,但是在AbstractConfiguredSecurityBuilder 中 performBuild 方法只是一个抽象方法,具体的实现在它的子类中。

2.3 再次看WebSecurity

通过上面的分析,可以了解到最终调的是子类的performBuild方法,看下WebSecurity的核心逻辑performBuild方法:

 @Overrideprotected Filter performBuild() throws Exception {Assert.state(!this.securityFilterChainBuilders.isEmpty(),() -> "At least one SecurityBuilder<? extends SecurityFilterChain> needs to be specified. "+ "Typically this is done by exposing a SecurityFilterChain bean "+ "or by adding a @Configuration that extends WebSecurityConfigurerAdapter. "+ "More advanced users can invoke " + WebSecurity.class.getSimpleName()+ ".addSecurityFilterChainBuilder directly");int chainSize = this.ignoredRequests.size() + this.securityFilterChainBuilders.size();List<SecurityFilterChain> securityFilterChains = new ArrayList<>(chainSize);for (RequestMatcher ignoredRequest : this.ignoredRequests) {securityFilterChains.add(new DefaultSecurityFilterChain(ignoredRequest));}for (SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder : this.securityFilterChainBuilders) {securityFilterChains.add(securityFilterChainBuilder.build());}FilterChainProxy filterChainProxy = new FilterChainProxy(securityFilterChains);if (this.httpFirewall != null) {filterChainProxy.setFirewall(this.httpFirewall);}if (this.requestRejectedHandler != null) {filterChainProxy.setRequestRejectedHandler(this.requestRejectedHandler);}filterChainProxy.afterPropertiesSet();Filter result = filterChainProxy;if (this.debugEnabled) {this.logger.warn("\n\n" + "********************************************************************\n"+ "**********        Security debugging is enabled.       *************\n"+ "**********    This may include sensitive information.  *************\n"+ "**********      Do not use in a production system!     *************\n"+ "********************************************************************\n\n");result = new DebugFilter(filterChainProxy);}this.postBuildAction.run();return result;}

从方法的返回值可以看出,返回的是一个Filter。

  1. 首先统计过滤器链的总条数,包括ignoredRequests(忽略的请求,通过WebSecurity配置),另外一个是securityFilterChainBuilders(通过HttpSecurity配置的过滤器链)
  2. 创建securityFilterChains的集合,将上面两个集合分别加入到此securityFilterChains中。
  3. 再通过securityFilterChains创建FilterChainProxy的实例并设置防火墙和拒绝策略的handler
  4. 最后返回这个FilterChainProxy实例

3 WebSecurityConfigurerAdapter

WebSecurityConfigurerAdapter 中的方法比较多,但是根据我们前面的分析,提纲挈领的方法就两个,一个是 init,还有一个 configure(WebSecurity web),其他方法都是为这两个方法服务的。那我们就来看下这两个方法:

 @Overridepublic void init(WebSecurity web) throws Exception {HttpSecurity http = getHttp();web.addSecurityFilterChainBuilder(http).postBuildAction(() -> {FilterSecurityInterceptor securityInterceptor = http.getSharedObject(FilterSecurityInterceptor.class);web.securityInterceptor(securityInterceptor);});}protected final HttpSecurity getHttp() throws Exception {if (this.http != null) {return this.http;}AuthenticationEventPublisher eventPublisher = getAuthenticationEventPublisher();this.localConfigureAuthenticationBldr.authenticationEventPublisher(eventPublisher);AuthenticationManager authenticationManager = authenticationManager();this.authenticationBuilder.parentAuthenticationManager(authenticationManager);Map<Class<?>, Object> sharedObjects = createSharedObjects();this.http = new HttpSecurity(this.objectPostProcessor, this.authenticationBuilder, sharedObjects);if (!this.disableDefaults) {applyDefaultConfiguration(this.http);ClassLoader classLoader = this.context.getClassLoader();List<AbstractHttpConfigurer> defaultHttpConfigurers = SpringFactoriesLoader.loadFactories(AbstractHttpConfigurer.class, classLoader);for (AbstractHttpConfigurer configurer : defaultHttpConfigurers) {this.http.apply(configurer);}}configure(this.http);return this.http;}protected void configure(HttpSecurity http) throws Exception {this.logger.debug("Using default configure(HttpSecurity). "+ "If subclassed this will potentially override subclass configure(HttpSecurity).");http.authorizeRequests((requests) -> requests.anyRequest().authenticated());http.formLogin();http.httpBasic();}

init 方法可以算是这里的入口方法了:首先调用 getHttp 方法进行 HttpSecurity 的初始化。HttpSecurity 的初始化,实际上就是配置了一堆默认的过滤器,配置完成后,最终还调用了 configure(http) 方法,该方法又配置了一些拦截器,不过在实际开发中,我们经常会重写 configure(http) 方法。

 @Overridepublic void configure(WebSecurity web) throws Exception {}

configure(WebSecurity web) 方法实际上是一个空方法,覆盖此方法以配置WebSecurity 。 例如,如果您希望忽略某些请求。 Spring Security 将忽略此方法中指定的端点,这意味着它不会保护它们免受 CSRF、XSS、Clickjacking 等攻击。 相反,如果您想保护端点免受常见漏洞的影响。

Spring Security 六 WebSecurityConfigurerAdapter相关推荐

  1. 【Spring Security】WebSecurityConfigurerAdapter被deprecated怎么办?官方推荐新的Security配置风格总结

    h 本期目录 背景 一. 前言 二. 配置HttpSecurity 三. 配置WebSecurity 四. 配置LDAP认证 五. 配置JDBC认证 六. In-Memory Authenticati ...

  2. Spring Security 实战干货:路径Uri中的 Ant 风格

    点击上方蓝色"程序猿DD",选择"设为星标" 回复"资源"获取独家整理的学习资料! 来源 | juejin.im/post/5c6b6b12 ...

  3. Spring Security 进阶干货:自定义配置类入口WebSecurityConfigurerAdapter

    1. 前言 今天我们要进一步的的学习如何自定义配置 Spring Security 我们已经多次提到了 WebSecurityConfigurerAdapter ,而且我们知道 Spring Boot ...

  4. Spring Security 实战干货:自定义配置类入口 WebSecurityConfigurerAdapter

    点击上方蓝色"程序猿DD",选择"设为星标" 回复"资源"获取独家整理的学习资料! 1. 前言 今天我们要进一步的的学习如何自定义配置 Sp ...

  5. SpringSecurity权限管理框架系列(六)-Spring Security框架自定义配置类详解(二)之authorizeRequests配置详解

    1.预置演示环境 这个演示环境继续沿用 SpringSecurit权限管理框架系列(五)-Spring Security框架自定义配置类详解(一)之formLogin配置详解的环境. 2.自定义配置类 ...

  6. Spring Security(三十六):12. Spring MVC Test Integration

    Spring Security provides comprehensive integration with Spring MVC Test Spring Security提供与Spring MVC ...

  7. SpringBoot集成Spring Security(一)登录注销

    同个人网站 https://www.serendipper-x.cn/,欢迎访问 ! SpringBoot集成Spring Security(二)注册 .密码加密.修改密码 写在前面 Spring S ...

  8. SpringBoot集成Spring Security(1)——入门程序

    因为项目需要,第一次接触 Spring Security,早就听闻 Spring Security 功能强大但上手困难,学习了几天出入门道,特整理这篇文章希望能让后来者少踩一点坑(本文附带实例程序,请 ...

  9. service获取selinux权限_Spring Boot 整合 Spring Security 示例实现前后分离权限注解 + JWT 登录认证...

    点击上方蓝色字体,选择"标星公众号" 优质文章,第一时间送达 99套Java企业级实战项目 4000G架构师资料 作者:Sans_ juejin.im/post/5da82f066 ...

最新文章

  1. Lidar激光雷达市场
  2. init/main.c中的void init(void)
  3. springboot起步配置和自动配置原理
  4. 前端学习(205):animation动画库
  5. 网络基础知识_你家的网络是这么布线的吗?家庭网络布线基础知识普及!
  6. 30+ 新鲜惊奇的 jQuery 插件与教程
  7. python两数相加有进退位_Leetcode_两数相加_python
  8. ue4 设置intellisence_UE4的配置界面写入
  9. C语言之文件读写探究(四):fwrite、fread(一次读写一块数据(二进制操作))
  10. .NET Remoting Basic(9)-上下文(CallContext)
  11. 海量数据排序问题一一 100G 数据,只有 100M 内存,怎么排序?
  12. FPN网络详解(知识点记录)
  13. 推荐几个编程学习网站,你值得拥有!
  14. 如何设置电脑的保护色?
  15. 从零开始用uniapp搭建一个APP
  16. Mysql数据库简单回滚操作
  17. Typora:Typora快捷键
  18. Linux中如何新建用户
  19. GitHub置顶半个月!78w字百亿级并发设计(全彩PDF),竟出自京东
  20. 「BJOI 2019」奥术神杖

热门文章

  1. iconv 转换字符编码,兼容VC转换
  2. 怎样才能学好一门编程语言?要怎样去学习才算成功?成为一名合格的程序员
  3. 英语思维导图大全 完型填空(二十)
  4. 2021 macbookpro14寸、16寸尺寸是多少
  5. lexyacc安装配置
  6. 解决vue运行报错:npm ERR! my-project@1.0.0 dev: `webpack-dev-server --inline --progress --config build/webp
  7. Springer期刊latex投稿需要上传的文件
  8. 菜鸟学数电1-如何看懂TTL名称
  9. 6-4 派生类使用基类的成员函数
  10. 软件产品案例分析(K米 APP)