springSecurity认证管理器

Posted by hcy on July 20, 2020

springSecurity认证管理器

​ SpringSecurity负责验证用户身份需要用到认证管理器(AuthenticationManager)。

认证管理器的接口很简单,只有一个方法,将用户名密码传入此认证器,如果不报错则为认证通过。

1
2
3
4
public interface AuthenticationManager {
	Authentication authenticate(Authentication authentication)
			throws AuthenticationException;
}

认证管理器

​ 在springSecurity里,我们可以配置多个认证管理器,将多个认证管理器合并成一个ProviderManager对外提供服务,只要有一个认证管理器认证通过,则表示通过,是一种责任链模式。

image-20200720125330662

​ 将多个authenticationProviders合并成一个的代码实现在这里

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder#performBuild 	
@Override
	protected ProviderManager performBuild() throws Exception {
        //将多个authenticationProviders合并成一个
		ProviderManager providerManager = new ProviderManager(authenticationProviders,
				parentAuthenticationManager);
        //验证通过是否擦除密码
		if (eraseCredentials != null) {
			providerManager.setEraseCredentialsAfterAuthentication(eraseCredentials);
		}
		if (eventPublisher != null) {
			providerManager.setAuthenticationEventPublisher(eventPublisher);
		}
		providerManager = postProcess(providerManager);
		return providerManager;
	}

配置认证管理器

配置的方式有两种,一种是重写下面的方法,配置好userDetailServicepasswoedEncoder

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(new UserDetailsService() {
            @Override
            public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
                //此处从数据库加载用户信息,并构造出userDetail的实例返回
                return null;
            }
        }).passwordEncoder(new PasswordEncoder() {
            @Override
            public String encode(CharSequence rawPassword) {
                return null;
            }

            //验证前传入的密码和数据库里的密码是否正确
            @Override
            public boolean matches(CharSequence rawPassword, String encodedPassword) {
                return false;
            }
        });

    }

上面的代码则会自动配置一个DaoAuthentication

​ 另一种方式是将userDetailServicepasswordEncoder 配置成spring的bean,框架就能自动查找到。

具体实现请查看在@EnableGlobalAuthentication注解是如何做的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
//配置初始化userDetail的配置
@Bean
public static InitializeUserDetailsBeanManagerConfigurer initializeUserDetailsBeanManagerConfigurer(ApplicationContext context) {
		return new InitializeUserDetailsBeanManagerConfigurer(context);
	}

//配置会被自动注入进来
@Autowired(required = false)
public void setGlobalAuthenticationConfigurers(
    List<GlobalAuthenticationConfigurerAdapter> configurers) {
    configurers.sort(AnnotationAwareOrderComparator.INSTANCE);
    this.globalAuthConfigurers = configurers;
}

//配置内部的实现
class InitializeUserDetailsManagerConfigurer
			extends GlobalAuthenticationConfigurerAdapter {
		@Override
		public void configure(AuthenticationManagerBuilder auth) throws Exception {
			if (auth.isConfigured()) {
				return;
			}
            //从容器内获取UserDetailsService
			UserDetailsService userDetailsService = getBeanOrNull(
					UserDetailsService.class);
			if (userDetailsService == null) {
				return;
			}
			//从容器内获取PasswordEncoder
			PasswordEncoder passwordEncoder = getBeanOrNull(PasswordEncoder.class);
			UserDetailsPasswordService passwordManager = getBeanOrNull(UserDetailsPasswordService.class);
		
            //创建DaoAuthenticationProvider
			DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
			provider.setUserDetailsService(userDetailsService);
			if (passwordEncoder != null) {
				provider.setPasswordEncoder(passwordEncoder);
			}
			if (passwordManager != null) {
				provider.setUserDetailsPasswordService(passwordManager);
			}
			provider.afterPropertiesSet();

			auth.authenticationProvider(provider);
		}


​ 上面两种配置方式都是可以的,本人更推荐第一种方式。一方面代码几种在一个配置文件里,比较方便查找,一方面如果想配置多个HttpSecurity,每个有独立的UserDetailService也更方便。

框架对两种配置方式如何选择的

​ 查看代码

1
org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter#authenticationManager

​ 通过configure方法重写,如果没重写则为自动配置,重写了就是手动配置。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
	protected AuthenticationManager authenticationManager() throws Exception {
		//如果没初始化则初始化
        if (!authenticationManagerInitialized) {
		//默认将disableLocalConfigureAuthenticationBldr设置true
            configure(localConfigureAuthenticationBldr);
		//使用本地自定义配置,就是配置1
			if (disableLocalConfigureAuthenticationBldr) {
				authenticationManager = authenticationConfiguration
						.getAuthenticationManager();
			}
		//使用自动配置,配置2
			else {
				authenticationManager = localConfigureAuthenticationBldr.build();
			}
			authenticationManagerInitialized = true;
		}
		return authenticationManager;
	}
	
		protected void configure(AuthenticationManagerBuilder auth) throws Exception {
		this.disableLocalConfigureAuthenticationBldr = true;
	}

转载请注明出处:https://www.huangchaoyu.com/2020/07/20/springSecurity认证管理器/