Spring Security实战--(五)认证和鉴权过程

前面几篇直接讲了Demo,但是可能还是有点混乱,这里再将整个认证过程梳理一下,加深对前面的理解

一、标准的身份验证方案

对一个系统来说,标准的安全身份验证方案应该按如下步骤:

  1. 用户使用用户名和密码登录;
  2. 系统验证用户的额密码正确,成功登录;
  3. 获取该用户的上下文,即该用户的角色列表;
  4. 为用户建立安全的上下文
  5. 用户可能会继续执行某些操作,该操作可能会受到访问控制机制的保护,该访问控制机制会根据当前安全上下文信息检查该操作所需的权限

其中,前四个步骤构成了认证过程,在SpringSecurity中流程如下:

  1. 获取用户名和密码,并将其组合到一个Authentication实例,一般为UsernamePasswordAuthenticationToken实例中
  2. token会被传送到AuthenticationManager实例进行验证
  3. 成功验证后,AuthenticationManager会返回一个Authentication实例
  4. 通过调用SecurityContextHolder.getContext().setAuthentication(…​)并传入返回的身份验证对象来建立安全上下文

来看一下涉及到的类

1.1 Authentication

继承了Principal类和序列化

public interface Authentication extends Principal, Serializable {
   
	
	/**
	 * 获得用户的权限信息列表
	 */
	Collection<? extends GrantedAuthority> getAuthorities();

	/**
	 * 密码信息,但认证后通常会被移除
	 */
	Object getCredentials();

	/**
	 * 
	 * 存储额外的认证请求信息,可能是IP地址等
	 */
	Object getDetails();

	/**
	 * 犯规身份信息
	 */
	Object getPrincipal();

	/**
	 * @return true if the token has been authenticated and the
	 */
	boolean isAuthenticated();

	/**
	 */
	void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException;
}

从上面的源码中可以看出,由这个接口的实现类,我们可以得到用户相关的
权限列表信息,密码、用户其他详细信息等重要信息

1.2 AuthenticationManager

AuthenticationManager是一个接口,正常系统应用中,登录是可以通过多种密码验证方式,如手机号+验证码,用户名/邮箱+密码等。这个时候就需要调用SpringSecurity对它的默认实现ProviderManager,但是它本身并不处理身份验证请求,而是委托给已经配置的AuthenticationProvider列表,依次查看是否可以执行身份验证,每个AuthenticationProvider程序都会引发一场或返回完全填充的Authentication对象。如上面所说的几种验证方式,只要通过一个AuthenticationProvider并返回Authentication对象,即可通过登录验证

public class ProviderManager implements AuthenticationManager, MessageSourceAware,
		InitializingBean {
   

	private AuthenticationEventPublisher eventPublisher = new NullEventPublisher();
	private List<AuthenticationProvider> providers = Collections.emptyList();
	protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
	private AuthenticationManager parent;
	private boolean eraseCredentialsAfterAuthentication = true;

	public ProviderManager(List<AuthenticationProvider> providers) {
   
		this(providers, null);
	}

	public ProviderManager(List<AuthenticationProvider> providers,
			AuthenticationManager parent) {
   
		Assert.notNull(providers, "providers list cannot be null");
		this.providers = providers;
		this.parent = parent;
		checkState();
	}

	private void checkState() {
   
		if (parent == null && providers.isEmpty()) {
   
			throw new IllegalArgumentException(
					"A parent AuthenticationManager or a list "
							+ "of AuthenticationProviders is required");
		}
	}

	/**
	 * 
	 */
	public Authentication authenticate(Authentication authentication)
			throws AuthenticationException {
   
		Class<? extends Authentication> toTest = authentication.getClass();
		AuthenticationException lastException = null;
		AuthenticationException parentException = null;
		Authentication result = null;
		Authentication parentResult = null;

		//遍历所有的AuthenticationProvider,因此进行认证
		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 | InternalAuthenticationServiceException e) {
   
				prepareException(e, authentication);
				// SEC-546: Avoid polling additional providers if auth failure is due to
				// invalid account status
				throw e;
			} catch (AuthenticationException e
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值