首页 > 其他分享 >在Spring Security中如何获取AuthenticationManager对象?

在Spring Security中如何获取AuthenticationManager对象?

时间:2022-11-24 22:35:10浏览次数:42  
标签:authenticationManager 对象 Spring Builder AuthenticationManager Manager Security 

有时需要使用AuthenticationManager(以下简称Manager)对象,可是这个对象不是Bean,没有直接保存在Spring的Bean库中。那么如何获取Spring Security中的这个对象呢?

在Spring Security 5.7.0-M2之前,通常会扩展WebSecurityConfigurerAdapter(以下简称Adapter)类来自定义网络安全配置。Adapter类中有一个方法authenticationManager()可以提供Manager对象。但是从Spring Security 5.7.0-M2开始,Adapter类就被弃用,再用此类中的authenticationManager()方法获取Manager对象就不合适了。

以下是Adapter#authenticationManager()方法的源码。

protected AuthenticationManager authenticationManager() throws Exception {
    if (!this.authenticationManagerInitialized) {
        configure(this.localConfigureAuthenticationBldr);
        if (this.disableLocalConfigureAuthenticationBldr) {
            this.authenticationManager = this.authenticationConfiguration.getAuthenticationManager();
        } else {
            this.authenticationManager = this.localConfigureAuthenticationBldr.build();
    }
    this.authenticationManagerInitialized = true;
    }
    return this.authenticationManager;
}

可以发现在该方法中使用Adapter类的私有字段authenticationConfiguration的getAuthenticationManager()方法获取Manager对象。而字段authenticationConfiguration是使用方法setAthenticationConfiguration()自动注入的,所以Spring的Bean库中存在Manager对象。由此可得到如下获取AuthenticationManager对象的方案一。

方案一:从Spring的Bean库中获取AuthenticationConfiguration(以下简称Configuration)对象,然后使用Configuration对象的getAuthenticationManager()方法获取Manager对象。(关于如何从Spring中获取Bean,本文不作介绍,请读者自行查阅资料了解)

继续查看Configuration#getAuthenticationManager()方法的源码。

public AuthenticationManager getAuthenticationManager() throws Exception {
    if (this.authenticationManagerInitialized) {
        return this.authenticationManager;
    }
    AuthenticationManagerBuilder authBuilder = this.applicationContext.getBean(AuthenticationManagerBuilder.class);
    if (this.buildingAuthenticationManager.getAndSet(true)) {
        return new AuthenticationManagerDelegator(authBuilder);
    }
    for (GlobalAuthenticationConfigurerAdapter config : this.globalAuthConfigurers) {
        authBuilder.apply(config);
    }
    this.authenticationManager = authBuilder.build();
    if (this.authenticationManager == null) {
        this.authenticationManager = getAuthenticationManagerBean();
    }
    this.authenticationManagerInitialized = true;
    return this.authenticationManager;
}

源码中展示的流程如下。

① 如果Configuration对象中已保存有Manager对象,则返回该对象。

② 如果Configuration对象中没有Manager对象,则从Spring的Bean库中获取AuthenticationManagerBuilder(以下简称Builder)对象。

③ 如果已经用Builder对象构建了Manager对象,则返回一个使用Builder对象初始化的AuthenticationManagerDelegator对象。

④ AuthenticationManagerDelegator是Manager的子类。该类代理了另一个Manager对象,被代理的Manager对象是使用Builder对象的getObject()方法获得的。Builder#getObject()的代码表明,在调用该方法前,需要先在Builder对象内构建一个Manager。也就是说可以从Spring的Bean库中获取Builder对象,然后用它的getObject()方法获得Manager对象。

@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
    if (this.delegate != null) {
        return this.delegate.authenticate(authentication);
    }
    synchronized (this.delegateMonitor) {
        if (this.delegate == null) {
            this.delegate = this.delegateBuilder.getObject();
            this.delegateBuilder = null;
        }
    }
    return this.delegate.authenticate(authentication);
}

⑤ 如果尚未使用Builder对象构建Manager对象,则先把Configuration的私有字段globalAuthConfigurers的数据应用在Builder对象上(私有字段globalAuthConfigurers是通过方法setGlobalAuthConfigurers()自动注入的)。

⑥ 然后使用Builder对象的build()方法构建Manager对象。

⑦ 在Builder#build()方法中,第一次调用该方法会使用doBuild()方法生成Manager对象(不分析doBuild()方法),并将这个对象缓存下来。以后再调用build()方法将会抛出AlreadyBuiltException异常。也就是说可以从Spring的Bean库中获取Builder对象,然后用它的build()方法获得Manager对象。

@Override
public final O build() throws Exception {
    if (this.building.compareAndSet(false, true)) {
        this.object = doBuild();
        return this.object;
    }
    throw new AlreadyBuiltException("This object has already been built");
}

⑧ 如果Builder对象未能成功构建Manager对象,则使用Configuration的私有方法lazyBean()方法获取Manager对象(不分析lazyBean()方法)。

上述流程表明,可以从Spring的Bean库中获取AuthenticationManagerBuilder对象,然后使用该对象的build()方法或getObject()方法获取AuthenticationManager对象。获取AuthenticationManager对象的方案二如下。

方案二:从Spring的Bean库中获取AuthenticationManagerBuilder对象,首先调用该对象的build()方法获取Manager对象,并对方法调用捕获AlreadyBuiltException异常。若捕获到异常,则在异常处理代码中调用Builder对象的getObject()方法获取Manager对象。

方案二可能有缺陷。在Configuration#getAuthenticationManager()方法的源码中可以看到步骤⑤对Builder对象对象做了处理,而方案二并没有做这种处理,推荐使用方案一。

标签:authenticationManager,对象,Spring,Builder,AuthenticationManager,Manager,Security,
From: https://www.cnblogs.com/cnblog-user/p/16923661.html

相关文章

  • SpringBoot整合Quartz
    1.Quartz1.1.Quartz简介Quartz是OpenSymphony开源组织在JobScheduling领域又一个开源项目,是完全由Java开发的一个开源任务日程管理系统,“任务进度管理器”就......
  • Spring 5 中文解析之测试篇-Spring测试介绍和单元测试
    微信公众号:测试本章介绍了Spring对集成测试的支持以及单元测试的最佳实践。Spring团队提倡测试驱动开发(TDD)。Spring的团队发现,正确使用控制反转(IoC)的确是简化单元测试和......
  • Spring 5 中文解析之测试篇-集成测试(下)
    3.6SpringMVC测试框架SpringMVC测试框架提供了一流的支持,可使用可与JUnit、TestNG或任何其他测试框架一起使用的流畅API测试SpringMVC代码。它基于​​spring-test​​......
  • Spring 5 中文解析之测试篇-集成测试(上)
    本节(本章其余部分)涵盖了Spring应用程序的集成测试。它包括以下主题:​​概要​​​​集成测试目标​​​​JDBC测试支持​​​​注解​​​​SpringTestContext框架​​​​......
  • Spring5全栈知识体系分享计划安排表
    Spring5全栈知识体系分享计划安排表第一阶段:翻译编号任务开始时间结束时间执行人完成进度1Spring52020-05-052020-10-01青年IT男已完成Spring-CoreSpring-TestingSpring-Da......
  • Spring Boot MongoDB How to remove _class from spring data mongodb collection
    摘要:在使用SpringBoot整合Mongodb的过程中,在做insert对象的时候,在Collection中会出现一个_class字段属性,出现这个问题的原因是在调用mongoTemplate的insert方法时,spring-......
  • Spring Boot 整合 RabbitMQ 之 Fanout Exchange模式 (三)
    摘要:那前面已经介绍过了Direct模式(一)Topic转发模式(二),这次介绍下FanoutExchange形式又叫广播形式,因此我们发送到路由器的消息会使得绑定到该路由器的每一个Queue接收......
  • Spring Boot 整合 RabbitMQ 之 Topic转发模式 (二)
    摘要:上一篇介绍了Direct模式的消息发生机制,这篇介绍下Topic转发模式的消息发生机制。一:首先我们看发送端,我们需要配置队列Queue,再配置交换机(Exchange),再把队列按照相应......
  • Setting Up Swagger 2 with a Spring REST API
    摘要:SpringMVC集成SwaggerUI一:SpringMVC介绍SpringWebMVC框架提供了模型-视图-控制器(MVC)体系结构和可用于开发灵活和松散耦合的Web应用程序的组件。MVC模式导致分......
  • Spring Boot+Spring Security+JWT 刷新Token之实现 RESTful Api 认证(二)
    作者:迷彩SpringBoot+SpringSecurity+JWT实现RESTfulApi认证(二)摘要上一篇​​javascript:void(0)​​我们已经实现了基本的登录和token认证接口,但是这里有个问题,对于......