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中。

原文地址:https://www.cnblogs.com/vincentren/p/15768910.html