Spring Security 认证过程几个重要对象

在这里插入图片描述

关于

  1. spring security 官网链接, 本次示例使用的版本为5.6.3:https://docs.spring.io/spring-security/reference/index.html
  2. 什么是认证:通俗点点理解来理解就是登录。随着互联网的发展,登录的方式也变得五花八门。较为常见的有账号密码登录,手机号验证码登录,三方登录等多种形式。

1. SpringSecurity中谁负责认证呢? AuthenticationProvider

事实上,上面的问题是不固定。用户可以通过很多组件来实现用户的认证。如通过Filter (Interceptor也类似)通过获取请求中传递的认证参数来做认证,或通过Controller中的接口来直接认证。

AuthenticationProvider 实际上是一个接口,具体实现要用户根据自身的需求来进行定制。
在这里插入图片描述
通过查看源代码很容易了解对应方法的逻辑。 一个是负责认证的业务逻辑。一个是决定当前 Provider是否可以对用户传递的认证主体进行认证。

package org.springframework.security.authentication;

import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;

public interface AuthenticationProvider {
	/**
	*	authentication: 认证的主体,开发者需要将需要认证的数据封装其中
	*	@return 认证通过后,将真实的用户信息进行封装返回
	**/
    Authentication authenticate(Authentication authentication) throws AuthenticationException;
	
	/*
	* 判断当前的authentication类型 本AuthenticationProvider是否可以处理
	* */
    boolean supports(Class<?> authentication);
}

2. 认证所需要的数据主体 Authentication

在这里插入图片描述
通过查看 Authentication 接口的源码发现很难看出一个所以然。所以我们可以通过其已有的实现类来查看其每个方法的用途。以及我们如何去进行自定义和拓展。

2.1 最熟悉以及经典的的实现 UsernamePasswordAuthenticationToken

如果你需要自定义认证主体,那么可以模仿 UsernamePasswordAuthenticationToken的实现,同时要注意我圈出来的位置。
在这里插入图片描述
首先,需要理解,为什么需要这样设计两个构造函数?
在这里插入图片描述
这和上面聊到的 AuthenticationProvider 中 authenticate 方法的 参数 和 返回值是对应的:

  1. 参数: 待认证的主体,调用的是第一个构造方法。
  2. 返回值: 认证完成后重新构造的主体,调用的是第二个构造方法。 通过注释也能看到,这个方法一般是在AuthenticationProvider中进行调用。

我们针对源码对几个重要对象进行分析:

/**
 * An {@link org.springframework.security.core.Authentication} implementation that is
 * designed for simple presentation of a username and password.
 * <p>
 * The <code>principal</code> and <code>credentials</code> should be set with an
 * <code>Object</code> that provides the respective property via its
 * <code>Object.toString()</code> method. The simplest such <code>Object</code> to use is
 * <code>String</code>.
 *
 * @author Ben Alex
 */
public class UsernamePasswordAuthenticationToken extends AbstractAuthenticationToken {

	private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;

	private final Object principal;

	private Object credentials;

	/**
	 * This constructor can be safely used by any code that wishes to create a
	 * <code>UsernamePasswordAuthenticationToken</code>, as the {@link #isAuthenticated()}
	 * will return <code>false</code>.
	 * 
	 */
	public UsernamePasswordAuthenticationToken(Object principal, Object credentials) {
		super(null);
		this.principal = principal;
		this.credentials = credentials;
		setAuthenticated(false);
	}

	/**
	 * 这个构造器应该只能被 AuthenticationManager 或者 AuthenticationProvider 的实现来使用,创建一个
	 * 被认证的对象。
	 * 
	 * This constructor should only be used by <code>AuthenticationManager</code> or
	 * <code>AuthenticationProvider</code> implementations that are satisfied with
	 * producing a trusted (i.e. {@link #isAuthenticated()} = <code>true</code>)
	 * authentication token.
	 * @param principal
	 * @param credentials
	 * @param authorities
	 */
	public UsernamePasswordAuthenticationToken(Object principal, Object credentials,
			Collection<? extends GrantedAuthority> authorities) {
		super(authorities);
		this.principal = principal;
		this.credentials = credentials;
		super.setAuthenticated(true); // must use super, as we override
	}

	@Override
	public Object getCredentials() {
		return this.credentials;
	}

	@Override
	public Object getPrincipal() {
		return this.principal;
	}

	@Override
	public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {
		Assert.isTrue(!isAuthenticated,
				"Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead");
		super.setAuthenticated(false);
	}

	@Override
	public void eraseCredentials() {
		super.eraseCredentials();
		this.credentials = null;
	}

}

3 Authentication(未认证) 的构造时机 (过滤器)

首先我们来分析一下UsernamePasswordAuthenticationFilter 的实现逻辑:
在这里插入图片描述
其中本类中的核心逻辑都在attemptAuthentication方法中,下面我们可以仔细分析一下这个方法的具体流程。
在这里插入图片描述
在此处,我们立马就明白了,在未认证前, UsernamePasswordAuthenticationToken 中的两个属性分别代表:

	// 用户名 
	private final Object principal;
	// 密码
	private Object credentials;

同时发现,按照我们前面的描述,认证的具体逻辑应该是由AuthenticationProvider 来来实现的,但此处为什么是AuthenticationManager 呢?

Spring Security 为了实现多种认证方式并存,于是抽象出一个 AuthenticationManager, 用来管理多个 AuthenticationProvider,每一个 AuthenticationProvider负责一种认证方式

下面我们就以Spring Security中默认的AuthenticationManager实现:ProviderManager 来看一下具体实现机制。
在这里插入图片描述
完全可以看出,其中认证的具体逻辑还是AuthenticationProvider进行实现。
在这里插入图片描述

4. AuthenticationManager

从语意上来说,这是不准确的。正确应该是 AuthenticationProviderManager,因为它实际上是来管理一些列 AuthenticaionProvider的。在其内部维护着一个AuthenticaionProvider数组。

在 引入 SpringSecurity的过程中,已经有一个AuthenticationManager对象被创建,如果我们需要使用它,一定要在配置类中将其以Bean的方式进行暴露。使得我们在使用的时候直接进行注入即可。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值