zoukankan      html  css  js  c++  java
  • spring security 源码学习(五)AuthenticationManager、ProviderManager、AuthenticationConfiguration

    在上上篇spring security 源码学习(三)WebSecurityConfiguration中对AuthenticationManager做过简单的介绍,这里,我们详细分析下AuthenticationManager。

    先简单描述下标题的这3个类有啥关系,AuthenticationManager是Spring Security用来认证的,ProviderManager是AuthenticationManager的一个实现,而AuthenticationConfiguration则是诞生(初始化)AuthenticationManager的配置类。

    AuthenticationManager的初始化是在HttpSecurity初始化时,顺带初始化的。。。开玩笑,AuthenticationManager也是非常重要的。让我们再回顾下

    	protected final HttpSecurity getHttp() throws Exception {
    		if (http != null) {
    			return http;
    		}
    
    		DefaultAuthenticationEventPublisher eventPublisher = objectPostProcessor
    				.postProcess(new DefaultAuthenticationEventPublisher());
    		localConfigureAuthenticationBldr.authenticationEventPublisher(eventPublisher);
    
    		AuthenticationManager authenticationManager = authenticationManager();
    		authenticationBuilder.parentAuthenticationManager(authenticationManager);
    		Map<Class<? extends Object>, Object> sharedObjects = createSharedObjects();
    
    		。。。。。。
    	}
    

       authenticationManager()方法如下:

        protected AuthenticationManager authenticationManager() throws Exception {
             //看是否初始化过,如果初始化过,不再初始化
            if (!authenticationManagerInitialized) {
                //提供自定义的地方,这边按照我们没加自定义那么执行的是 this.disableLocalConfigureAuthenticationBldr = true;
                configure(localConfigureAuthenticationBldr);
                if (disableLocalConfigureAuthenticationBldr) {
                    authenticationManager = authenticationConfiguration
                            .getAuthenticationManager();
                }
                else {
                    authenticationManager = localConfigureAuthenticationBldr.build();
                }
                authenticationManagerInitialized = true;
            }
            return authenticationManager;
        }

      根据上面的注释,可以看到初始化就在authenticationConfiguration.getAuthenticationManager();让我们来看下这段代码:

        public AuthenticationManager getAuthenticationManager() throws Exception {
            if (this.authenticationManagerInitialized) {
                return this.authenticationManager;
            }
            //执行了new AuthenticationManagerBuilder(objectPostProcessor);
            AuthenticationManagerBuilder authBuilder = authenticationManagerBuilder(
                    this.objectPostProcessor);
         //如果是第一次,那么这里就会把值改为true,表示正在构建AuthenticationManager,不会进入到if体里去
            //如果正在构建时又来到这,则会返回一个包装了AuthenticationManagerBuilder的AuthenticationManager的代理类AuthenticationManagerDelegator
            if (this.buildingAuthenticationManager.getAndSet(true)) {
                return new AuthenticationManagerDelegator(authBuilder);
            }
            //这里就是在上一次未讲的地方,这里出现了5个配置类
            for (GlobalAuthenticationConfigurerAdapter config : globalAuthConfigurers) {
           //老样子,将配置类加入到AuthenticationManagerBuilder的父类AbstractConfiguredSecurityBuilder的
           //LinkedHashMap<Class<? extends SecurityConfigurer<O, B>>, List<SecurityConfigurer<O, B>>> configurers属性中,待build
                authBuilder.apply(config);
            }
         //老规矩,老的build那套
            authenticationManager = authBuilder.build();
    
            if (authenticationManager == null) {
                authenticationManager = getAuthenticationManagerBean();
            }
    
            this.authenticationManagerInitialized = true;
            return authenticationManager;
        }

      GlobalAuthenticationConfigurerAdapter在spring中的几个实例是哪来的呢?

    一部分是从这里来的AuthenticationConfiguration,而AuthenticationConfiguration则是被EnableGlobalAuthentication引入的,EnableGlobalAuthentication则是在EnableWebSecurity时引入的,这么说有点抽象,来几个代码就清楚了

    @Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME)
    @Target(value = { java.lang.annotation.ElementType.TYPE })
    @Documented
    @Import({ WebSecurityConfiguration.class,
            SpringWebMvcImportSelector.class })
    @EnableGlobalAuthentication
    @Configuration
    public @interface EnableWebSecurity {
    
        /**
         * Controls debugging support for Spring Security. Default is false.
         * @return if true, enables debug support with Spring Security
         */
        boolean debug() default false;
    }
    @Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME)
    @Target(value = { java.lang.annotation.ElementType.TYPE })
    @Documented
    @Import(AuthenticationConfiguration.class)
    @Configuration
    public @interface EnableGlobalAuthentication {
    }

      

    @Configuration
    @Import(ObjectPostProcessorConfiguration.class)
    public class AuthenticationConfiguration {
    
        private AtomicBoolean buildingAuthenticationManager = new AtomicBoolean();
    
        private ApplicationContext applicationContext;
    
        private AuthenticationManager authenticationManager;
    
        private boolean authenticationManagerInitialized;
    
        private List<GlobalAuthenticationConfigurerAdapter> globalAuthConfigurers = Collections
                .emptyList();
    
        private ObjectPostProcessor<Object> objectPostProcessor;
    
        @Bean
        public AuthenticationManagerBuilder authenticationManagerBuilder(
                ObjectPostProcessor<Object> objectPostProcessor) {
            return new AuthenticationManagerBuilder(objectPostProcessor);
        }
    
        @Bean
        public static GlobalAuthenticationConfigurerAdapter enableGlobalAuthenticationAutowiredConfigurer(
                ApplicationContext context) {
            return new EnableGlobalAuthenticationAutowiredConfigurer(context);
        }
    
        @Bean
        public static InitializeUserDetailsBeanManagerConfigurer initializeUserDetailsBeanManagerConfigurer(ApplicationContext context) {
            return new InitializeUserDetailsBeanManagerConfigurer(context);
        }
    
        @Bean
        public static InitializeAuthenticationProviderBeanManagerConfigurer initializeAuthenticationProviderBeanManagerConfigurer(ApplicationContext context) {
            return new InitializeAuthenticationProviderBeanManagerConfigurer(context);
        }
    
        public AuthenticationManager getAuthenticationManager() throws Exception {
            if (this.authenticationManagerInitialized) {
                return this.authenticationManager;
            }
            AuthenticationManagerBuilder authBuilder = authenticationManagerBuilder(
                    this.objectPostProcessor);
            if (this.buildingAuthenticationManager.getAndSet(true)) {
                return new AuthenticationManagerDelegator(authBuilder);
            }
    
            for (GlobalAuthenticationConfigurerAdapter config : globalAuthConfigurers) {
                authBuilder.apply(config);
            }
    
            authenticationManager = authBuilder.build();
    
            if (authenticationManager == null) {
                authenticationManager = getAuthenticationManagerBean();
            }
    
            this.authenticationManagerInitialized = true;
            return authenticationManager;
        }
    
        @Autowired(required = false)
        public void setGlobalAuthenticationConfigurers(
                List<GlobalAuthenticationConfigurerAdapter> configurers) throws Exception {
            Collections.sort(configurers, AnnotationAwareOrderComparator.INSTANCE);
            this.globalAuthConfigurers = configurers;
        }
    
        @Autowired
        public void setApplicationContext(ApplicationContext applicationContext) {
            this.applicationContext = applicationContext;
        }
    
        @Autowired
        public void setObjectPostProcessor(ObjectPostProcessor<Object> objectPostProcessor) {
            this.objectPostProcessor = objectPostProcessor;
        }
    
        @SuppressWarnings("unchecked")
        private <T> T lazyBean(Class<T> interfaceName) {
            LazyInitTargetSource lazyTargetSource = new LazyInitTargetSource();
            String[] beanNamesForType = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
                    applicationContext, interfaceName);
            if (beanNamesForType.length == 0) {
                return null;
            }
            Assert.isTrue(beanNamesForType.length == 1,
                    "Expecting to only find a single bean for type " + interfaceName
                            + ", but found " + Arrays.asList(beanNamesForType));
            lazyTargetSource.setTargetBeanName(beanNamesForType[0]);
            lazyTargetSource.setBeanFactory(applicationContext);
            ProxyFactoryBean proxyFactory = new ProxyFactoryBean();
            proxyFactory = objectPostProcessor.postProcess(proxyFactory);
            proxyFactory.setTargetSource(lazyTargetSource);
            return (T) proxyFactory.getObject();
        }
    
        private AuthenticationManager getAuthenticationManagerBean() {
            return lazyBean(AuthenticationManager.class);
        }
    
        private static class EnableGlobalAuthenticationAutowiredConfigurer extends
                GlobalAuthenticationConfigurerAdapter {
            private final ApplicationContext context;
            private static final Log logger = LogFactory
                    .getLog(EnableGlobalAuthenticationAutowiredConfigurer.class);
    
            public EnableGlobalAuthenticationAutowiredConfigurer(ApplicationContext context) {
                this.context = context;
            }
    
            @Override
            public void init(AuthenticationManagerBuilder auth) {
                Map<String, Object> beansWithAnnotation = context
                        .getBeansWithAnnotation(EnableGlobalAuthentication.class);
                if (logger.isDebugEnabled()) {
                    logger.debug("Eagerly initializing " + beansWithAnnotation);
                }
            }
        }
    
        /**
         * Prevents infinite recursion in the event that initializing the
         * AuthenticationManager.
         *
         * @author Rob Winch
         * @since 4.1.1
         */
        static final class AuthenticationManagerDelegator implements AuthenticationManager {
            private AuthenticationManagerBuilder delegateBuilder;
            private AuthenticationManager delegate;
            private final Object delegateMonitor = new Object();
    
            AuthenticationManagerDelegator(AuthenticationManagerBuilder delegateBuilder) {
                Assert.notNull(delegateBuilder, "delegateBuilder cannot be null");
                this.delegateBuilder = delegateBuilder;
            }
    
            @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);
            }
    
            @Override
            public String toString() {
                return "AuthenticationManagerDelegator [delegate=" + this.delegate + "]";
            }
        }
    }

      由上面的一连串代码,可以看到有3个GlobalAuthenticationConfigurerAdapter的子类,EnableGlobalAuthenticationAutowiredConfigurer、InitializeUserDetailsBeanManagerConfigurer、InitializeAuthenticationProviderBeanManagerConfigurer被加入到了AuthenticationConfiguration中,待用来初始化,那么还有2个是哪来的

    EnableGlobalAuthenticationAutowiredConfigurer 

        private static class EnableGlobalAuthenticationAutowiredConfigurer extends
                GlobalAuthenticationConfigurerAdapter {
            private final ApplicationContext context;
            private static final Log logger = LogFactory
                    .getLog(EnableGlobalAuthenticationAutowiredConfigurer.class);
    
            public EnableGlobalAuthenticationAutowiredConfigurer(ApplicationContext context) {
                this.context = context;
            }
    
            @Override
            public void init(AuthenticationManagerBuilder auth) {
                Map<String, Object> beansWithAnnotation = context
                        .getBeansWithAnnotation(EnableGlobalAuthentication.class);
                if (logger.isDebugEnabled()) {
                    logger.debug("Eagerly initializing " + beansWithAnnotation);
                }
            }
        }

    从源码中可以看出,这个类其实没干啥,就是会触发下注解了@EnableGlobalAuthentication的bean的初始化。

    InitializeUserDetailsBeanManagerConfigurer

    @Order(InitializeUserDetailsBeanManagerConfigurer.DEFAULT_ORDER)
    class InitializeUserDetailsBeanManagerConfigurer
            extends GlobalAuthenticationConfigurerAdapter {
    
        static final int DEFAULT_ORDER = Ordered.LOWEST_PRECEDENCE - 5000;
    
        private final ApplicationContext context;
    
        /**
         * @param context
         */
        public InitializeUserDetailsBeanManagerConfigurer(ApplicationContext context) {
            this.context = context;
        }
    
        @Override
        public void init(AuthenticationManagerBuilder auth) throws Exception {
            auth.apply(new InitializeUserDetailsManagerConfigurer());
        }
    
        class InitializeUserDetailsManagerConfigurer
                extends GlobalAuthenticationConfigurerAdapter {
            @Override
            public void configure(AuthenticationManagerBuilder auth) throws Exception {
                if (auth.isConfigured()) {
                    return;
                }
                UserDetailsService userDetailsService = getBeanOrNull(
                        UserDetailsService.class);
                if (userDetailsService == null) {
                    return;
                }
    
                PasswordEncoder passwordEncoder = getBeanOrNull(PasswordEncoder.class);
    
                DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
                provider.setUserDetailsService(userDetailsService);
                if (passwordEncoder != null) {
                    provider.setPasswordEncoder(passwordEncoder);
                }
           //将上面new的DaoAuthenticationProvider加入到AuthenticationManagerBuilder的List<AuthenticationProvider> authenticationProviders中。
                auth.authenticationProvider(provider);
            }
    
            /**
             * @return
             */
            private <T> T getBeanOrNull(Class<T> type) {
                String[] userDetailsBeanNames = InitializeUserDetailsBeanManagerConfigurer.this.context
                        .getBeanNamesForType(type);
                if (userDetailsBeanNames.length != 1) {
                    return null;
                }
    
                return InitializeUserDetailsBeanManagerConfigurer.this.context
                        .getBean(userDetailsBeanNames[0], type);
            }
        }
    }

    从源码中可以看出来,这个类的init是将InitializeUserDetailsManagerConfigurer加入了AuthenticationManagerBuilder用于configure,而InitializeUserDetailsManagerConfigurer的configure则是从容器中获取UserDetailsService和PasswordEncoder的实现类,如果UserDetailsService没有实现类,则直接返回,有的话则new一个DaoAuthenticationProvider加入到AuthenticationManagerBuilder的List<AuthenticationProvider> authenticationProviders中。

    InitializeAuthenticationProviderBeanManagerConfigurer

    @Order(InitializeAuthenticationProviderBeanManagerConfigurer.DEFAULT_ORDER)
    class InitializeAuthenticationProviderBeanManagerConfigurer
            extends GlobalAuthenticationConfigurerAdapter {
    
        static final int DEFAULT_ORDER = InitializeUserDetailsBeanManagerConfigurer.DEFAULT_ORDER
                - 100;
    
        private final ApplicationContext context;
    
        /**
         * @param context the ApplicationContext to look up beans.
         */
        public InitializeAuthenticationProviderBeanManagerConfigurer(
                ApplicationContext context) {
            this.context = context;
        }
    
        @Override
        public void init(AuthenticationManagerBuilder auth) throws Exception {
            auth.apply(new InitializeUserDetailsManagerConfigurer());
        }
    
        class InitializeUserDetailsManagerConfigurer
                extends GlobalAuthenticationConfigurerAdapter {
            @Override
            public void configure(AuthenticationManagerBuilder auth) throws Exception {
                if (auth.isConfigured()) {
                    return;
                }
                AuthenticationProvider authenticationProvider = getBeanOrNull(
                        AuthenticationProvider.class);
                if (authenticationProvider == null) {
                    return;
                }
    
    
                auth.authenticationProvider(authenticationProvider);
            }
    
            /**
             * @return
             */
            private <T> T getBeanOrNull(Class<T> type) {
                String[] userDetailsBeanNames = InitializeAuthenticationProviderBeanManagerConfigurer.this.context
                        .getBeanNamesForType(type);
                if (userDetailsBeanNames.length != 1) {
                    return null;
                }
    
                return InitializeAuthenticationProviderBeanManagerConfigurer.this.context
                        .getBean(userDetailsBeanNames[0], type);
            }
        }
    }

    从源码中可以看出,从Spring的容器中获取AuthenticationProvider的实现类,加入到uthenticationManagerBuilder的List<AuthenticationProvider> authenticationProviders中。

    ps:注意InitializeUserDetailsBeanManagerConfigurer、InitializeAuthenticationProviderBeanManagerConfigurer这两个类都是懒加载,目的就是将容器中的所有AuthenticationProvider的实现类加入到uthenticationManagerBuilder的List<AuthenticationProvider> authenticationProviders中。

  • 相关阅读:
    windows bat
    如何重置postgresql用户密码
    SQL Server如何修改登录密码
    MySQL操作题(mysql_V20190307)
    MariaDB主从备份
    MySQL&MariaDB数据库备份脚本
    SQL语句大全,所有的SQL都在这里
    数据库操作语句大全(sql)
    Python代码,将图片转为了Excel
    亚晨yacn软件config数据获取
  • 原文地址:https://www.cnblogs.com/vincentren/p/15768910.html
Copyright © 2011-2022 走看看