欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

spring security 认证流程

程序员文章站 2022-05-05 15:17:26
...

1.认证流程

spring security 认证流程
(1)用户发起登录请求后,首先进入 UsernamePasswordAuthenticationFilter(AbstractAuthenticationProcessingFilter)

AbstractAuthenticationProcessingFilter中doFilter方法
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
			throws IOException, ServletException {

		HttpServletRequest request = (HttpServletRequest) req;
		HttpServletResponse response = (HttpServletResponse) res;
		
		// 1.判断请求是否是login和post,UsernamePasswordAuthenticationFilter的构造方法
		if (!requiresAuthentication(request, response)) {
			chain.doFilter(request, response);

			return;
		}

		if (logger.isDebugEnabled()) {
			logger.debug("Request is to process authentication");
		}

		Authentication authResult;

		try {
			//2.调用子类UsernamePasswordAuthenticationFilter的attemptAuthentication方法,
			//在attemptAuthentication方法中创建了一个authenticated为false(即未授权)的UsernamePasswordAuthenticationToken,并传递给AuthenticationManager().authenticate()这个方法进行认证,
			//认证成功后,返回一个authenticated=true的UsernamePasswordAuthenticationToken对象
			authResult = attemptAuthentication(request, response);
			if (authResult == null) {
				// return immediately as subclass has indicated that it hasn't completed
				// authentication
				return;
			}
			sessionStrategy.onAuthentication(authResult, request, response);
		}
		catch (InternalAuthenticationServiceException failed) {
			logger.error(
					"An internal error occurred while trying to authenticate the user.",
					failed);
			// 3.认证失败后通过调用AuthenticationFailureHandler 的onAuthenticationFailure 接口进行失败处理,可以通过继承AuthenticationFailureHandler 进行自定义失败逻辑
			unsuccessfulAuthentication(request, response, failed);

			return;
		}
		catch (AuthenticationException failed) {
			// Authentication failed
			// 4.认证失败后通过调用AuthenticationFailureHandler 的onAuthenticationFailure 接口进行失败处理,可以通过继承AuthenticationFailureHandler 进行自定义失败逻辑
			unsuccessfulAuthentication(request, response, failed);

			return;
		}

		// Authentication success
		if (continueChainBeforeSuccessfulAuthentication) {
			chain.doFilter(request, response);
		}
		// 5.认证成功后调用AuthenticationSuccessHandler 的onAuthenticationSuccess 接口进行成功处理,也可以通过继承AuthenticationSuccessHandler 自行实现成功处理逻辑
		successfulAuthentication(request, response, chain, authResult);
	}
public Authentication attemptAuthentication(HttpServletRequest request,
			HttpServletResponse response) throws AuthenticationException {
		if (postOnly && !request.getMethod().equals("POST")) {
			throw new AuthenticationServiceException(
					"Authentication method not supported: " + request.getMethod());
		}

		String username = obtainUsername(request);
		String password = obtainPassword(request);

		if (username == null) {
			username = "";
		}

		if (password == null) {
			password = "";
		}

		username = username.trim();
		// 根据用户名和密码生成 未认证的UsernamePasswordAuthenticationToken 
		UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(
				username, password);

		setDetails(request, authRequest);
		//将生成未认证的UsernamePasswordAuthenticationToken 交给AuthenticationManager 处理
		return this.getAuthenticationManager().authenticate(authRequest);
	}

AuthenticationManager 本身不包含认证逻辑,核心用来管理所有的AuthenticationProvider,通过交给合适的AuthenticationProvider来实现认证

(2)跳转到ProviderManager ,该类是AuthenticationManager 的实现类
spring security 认证流程
不同的登录逻辑他的认证方式是不一样的,
springsecurity 支持多种认证逻辑,每一种认证逻辑的认证方式其实就是一种AuthenticationProvider。通过getProviders方法获取所有的AuthenticationProvider,通过supports来判断是否支持当前认证逻辑。
当选择好一个合适的AuthenticationProvider后,通过provider.authenticate()来让AuthenticationProvider 进行认证。
(3)传统表单登录的AuthenticationProvider主要是由AbstractUserDetailsAuthenticationProvider 来进行处理的,我们来看下它的authenticate()

首先调用retrieveUser来获取到数据库用户信息

spring security 认证流程
当我们成功的读取UserDetails之后,下面开始对其进行认证

spring security 认证流程
在上图中,我们可以看到认证校验分为 前校验、附加校验和后校验,如果任何一个校验出错,就会抛出相应的异常。所有校验都通过后,调用 createSuccessAuthentication() 返回认证信息。
spring security 认证流程

createSuccessAuthentication方法中,重新new了一个UsernamePasswordAuthenticationToken,并将authorities传进去,设置authenticated为true
(4)至此认证信息被传递回UsernamePasswordAuthenticationFilter 中,在 UsernamePasswordAuthenticationFilter 的父类 AbstractAuthenticationProcessingFilter 的 doFilter() 中,会根据认证的成功或者失败调用相应的 handler:
spring security 认证流程

二、多个请求共享session用户信息

spring security通过session保存用户认真信息
下面将 Spring Security 的认证流程补充完整,如下图:

spring security 认证流程
在上一节认证成功的 successfulAuthentication()方法中,有一行语句:

SecurityContextHolder.getContext().setAuthentication(authResult);

三、获取用户信息

通过调用 SecurityContextHolder.getContext().getAuthentication() 就能够取得认证信息

@GetMapping("/me")
@ResponseBody
public Object me() {
    return SecurityContextHolder.getContext().getAuthentication();
}

上面的写法有点啰嗦,我们可以简写成下面这种, Spring MVC 会自动帮我们从 Spring Security 中注入:

@GetMapping("/me")
@ResponseBody
public Object me(Authentication authentication) {
    return authentication;
}

如果你仅想获取 UserDetails 对象,也是可以的,写法如下:

@GetMapping("/me")
@ResponseBody
public Object me(@AuthenticationPrincipal UserDetails userDetails) {
    return userDetails;
}

转载https://jitwxs.blog.csdn.net/article/details/84703690

相关标签: springboot