spring security 5 (4)-认证流程

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wangb_java/article/details/86625931

本篇介绍登录时的认证流程,及其相关的重要概念接口等,现在只需要有一个基本概念,以后将以此为基础介绍自定义配置,到时结合本篇会更加清晰。

SecurityContext

用户登录时,会将用户相关信息组装成一个Authentication对象,而SecurityContext的主要作用就是保存Authentication。并且 SecurityContext会通过session来维持状态,所以登录后每次请求都可以从session中获取当前用户Authentication,这是系统内部实现的。我们可直接使用系统封装好的方法来获取当前用户Authentication对象,如下

SecurityContextHolder.getContext().getAuthentication();

Authentication

这个Authentication也是第2篇表达示中的authentication,其源码如下

public interface Authentication extends Principal, Serializable {
	Collection<? extends GrantedAuthority> getAuthorities();//用户权限集合
	Object getCredentials();//密码类参数
	Object getDetails();    //其他登录参数
	Object getPrincipal();//用户信息,如用户名
	boolean isAuthenticated();//认证状态:是否认证过
	void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException;//设置认证状态
  • 第3篇的UserDetails,就是这里的getPrincipal(),用户登录后,通过以下方法就可以获取到UserDetails。
SecurityContextHolder.getContext().getAuthentication().getPrincipal()
  • Object类型表明,你在自定义配置实现时自由度非常高。UserDetails只是系统默认的getPrincipal()类型,在自定义配置中可以是任何类型,以后会讲。
  • getDetails()是用户/密码以外的额外参数,根据你的业务需要而定,比如登录时可能还会使用验证码参数。
  • isAuthenticated用于标识当前Authentication是否认证过,下面会讲。
  • UsernamePasswordAuthenticationToken是Authentication的默认实现类,了解下其源码会更清晰。

AuthenticationManager

用户登录时,首先生成的Authentication是未认证状态,交由AuthenticationManager认证。AuthenticationManager会将Authentication中的用户名/密码与UserDetails中的用户名/密码对比,完成认证工作,认证成功后会生成一个已认证状态的Authentication,此时就会写入到SecurityContext。在用户有后续请求时,可从Authentication中检查权限

认证流程

以下例子出自官方文档,这是一个最简化的认证流程,而且省略了UserDetails,只做了简单认证。

public class AuthenticationExample {
	private static AuthenticationManager am = new SampleAuthenticationManager();

	public static void main(String[] args) throws Exception {
		BufferedReader in = new BufferedReader(new InputStreamReader(System.in));

		while (true) {
                        //模拟输入用户名密码
			System.out.println("Please enter your username:");
			String name = in.readLine();
			System.out.println("Please enter your password:");
			String password = in.readLine();
			try {
				//根据用户名/密码,生成未认证Authentication
				Authentication request = new UsernamePasswordAuthenticationToken(name, password);
                                //交给AuthenticationManager 认证
				Authentication result = am.authenticate(request);
				//将已认证的Authentication放入SecurityContext
				SecurityContextHolder.getContext().setAuthentication(result);
				break;
			} catch (AuthenticationException e) {
				System.out.println("Authentication failed: " + e.getMessage());
			}
		}
		System.out.println("Successfully authenticated. Security context contains: "
				+ SecurityContextHolder.getContext().getAuthentication());
	}
}
//认证类
class SampleAuthenticationManager implements AuthenticationManager {
        //配置一个简单的用户权限集合
	static final List<GrantedAuthority> AUTHORITIES = new ArrayList<GrantedAuthority>();
	static {
		AUTHORITIES.add(new SimpleGrantedAuthority("ROLE_USER"));
	}

	public Authentication authenticate(Authentication auth) throws AuthenticationException {
                //如果用户名和密码一致,则登录成功,这里只做了简单认证
		if (auth.getName().equals(auth.getCredentials())) {
			//认证成功,生成已认证Authentication,比未认证多了权限
			return new UsernamePasswordAuthenticationToken(auth.getName(), auth.getCredentials(), AUTHORITIES);
		}
		throw new BadCredentialsException("Bad Credentials");
	}
}

认证过滤器

main方法中的代码就是模拟认证过滤器做的事,当认证过滤器拦截到/login登录请求,就会开始执行。

猜你喜欢

转载自blog.csdn.net/wangb_java/article/details/86625931