SpringOauth2.0源码分析之ProviderManager(二)

1.概述

上一章节:

  1. SpringOauth2.0源码分析之认证流程分析(一)

在SpringOauth2.0中,所有的认证服务,均通过ProviderManager认证管理中心进行认证。通过分析ProviderManager,可以理解SpringOauth2.0认证的细节。也是整个流程中最核心的环节之一。

2.ProviderManager 的类结构

ProviderManager 继承实现AuthenticationManager接口。

public class ProviderManager implements AuthenticationManager, MessageSourceAware,
		InitializingBean {
		.....
		}

AuthenticationManager 接口只有一个方法:Authentication authenticate(Authentication authentication)
throws AuthenticationException,该方法传入一个Authentication 的实例,认证成功返回的是 Authentication 的一个具体实例。

public interface AuthenticationManager {
	Authentication authenticate(Authentication authentication)
			throws AuthenticationException;
}

Authentication 接口描述:

public interface Authentication extends Principal, Serializable {
// 返回当前用户的权限列表
	Collection<? extends GrantedAuthority> getAuthorities();
// 获取当前认证的密码
	Object getCredentials();
//存储有关身份验证请求的其他详细信息。 这些可能是IP地址,证书序列号等
	Object getDetails();
//获取当前用户名
	Object getPrincipal();
// 获取是否已经认证
	boolean isAuthenticated();
// 设置是否通过认证
	void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException;
}
2.1 AuthenticationManager 接口实现类

AuthenticationManager 部分实现类,在当前的用户名密码认证的过程中,主要的核心类是:ProviderManager
在这里插入图片描述

2.2 Authentication 接口实现类

列举出Authentication 部分实现核心类,在用户名密码认证过程中,主要使用的核心类是:UsernamePasswordAuthenticationToken。
在这里插入图片描述

3.ProviderManager 类的成员变量和代码

ProviderManager 类核心成员变量和实现代码,限于篇幅,只保留主要的

public class ProviderManager implements AuthenticationManager, MessageSourceAware,
		InitializingBean {
	// 认证提供者列表。认证提供者主要根据传入的不同的 Authentication 决定使用哪种认证方式
	// providers 集合在项目启动的时候会被初始化进去。主要初始化的提供者有两个:
	// AnonymousAuthenticationProvider  和 DaoAuthenticationProvider
	private List<AuthenticationProvider> providers = Collections.emptyList();
	
	// 上一级认证管理者,一般情况下用不到
	private AuthenticationManager parent;
	
	// 构造函数初始化
	public ProviderManager(List<AuthenticationProvider> providers,
			AuthenticationManager parent) {
		Assert.notNull(providers, "providers list cannot be null");
		this.providers = providers;
		this.parent = parent;
		checkState();
	}
	
	// 通过传入不同的 authentication ,决定使用哪种认证方式去认证当前用户
	// 每个authentication 对应着一个认证策略
	public Authentication authenticate(Authentication authentication)
			throws AuthenticationException {
		Class<? extends Authentication> toTest = authentication.getClass();
		AuthenticationException lastException = null;
		Authentication result = null;
		boolean debug = logger.isDebugEnabled();
		// 遍历当前集合,找到和authentication 匹配的认证方式。
		for (AuthenticationProvider provider : getProviders()) {
		 // 判断是否支持当前认证方式
			if (!provider.supports(toTest)) {
				continue;
			}
			if (debug) {
				logger.debug("Authentication attempt using "
						+ provider.getClass().getName());
			}
			try {
				// 调用当前认证方式的具体实现类
				result = provider.authenticate(authentication);
				if (result != null) {
					copyDetails(authentication, result);
					break;
				}
			}
			catch (AccountStatusException e) {
				prepareException(e, authentication);
				// SEC-546: Avoid polling additional providers if auth failure is due to
				// invalid account status
				throw e;
			}
			catch (InternalAuthenticationServiceException e) {
				prepareException(e, authentication);
				throw e;
			}
			catch (AuthenticationException e) {
				lastException = e;
			}
		}
		// 如果当前认证返回结果为空,则调用类初始化的上一级认证方式
		if (result == null && parent != null) {
			// Allow the parent to try.
			try {
				result = parent.authenticate(authentication);
			}
			catch (ProviderNotFoundException e) {
				// ignore as we will throw below if no other exception occurred prior to
				// calling parent and the parent
				// may throw ProviderNotFound even though a provider in the child already
				// handled the request
			}
			catch (AuthenticationException e) {
				lastException = e;
			}
		}
		if (result != null) {
			if (eraseCredentialsAfterAuthentication
					&& (result instanceof CredentialsContainer)) {
				// Authentication is complete. Remove credentials and other secret data
				// from authentication
				// 对当前认证通过的authentication 信息进行脱敏处理
				((CredentialsContainer) result).eraseCredentials();
			}
			eventPublisher.publishAuthenticationSuccess(result);
			返回当前的认证结果
			return result;
		}
		if (lastException == null) {
			lastException = new ProviderNotFoundException(messages.getMessage(
					"ProviderManager.providerNotFound",
					new Object[] { toTest.getName() },
					"No AuthenticationProvider found for {0}"));
		}
		prepareException(lastException, authentication);
		throw lastException;
	}
}

ProviderManager 认证管理中心,相当于一个策略模板,根据传入的认证信息,选择不同的认证处理器进行处理。达到了认证集中管理的效果。也秉承了设计模式里面的高内聚低耦合。

4.AuthenticationProvider 接口详解

针对不同认证信息,AuthenticationProvider 提供了不同的对应策略。

public interface AuthenticationProvider {
 // 具体的认证细节
	Authentication authenticate(Authentication authentication)
			throws AuthenticationException;
	// 判断是否支持当前认证
	boolean supports(Class<?> authentication);
}
4.1 AuthenticationProvider 核心实现类

在这里插入图片描述
在密码认证的过程中,其核心的认证类是:AbstractUserDetailsAuthenticationProvider 和DaoAuthenticationProvider。这里使用了设计模式中的模板方法进行实现。

5.结语

通过ProviderManager 类结构和成员变量的分析,可以清楚的知道,ProviderManager 提供了策略模板的作用,通过传入不同的认证信息,找到对应的认证提供者。对信息进行认证。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值