ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

springboot服务认证方式Tomcat中session创建管理流程分析

2022-01-18 14:30:11  阅读:217  来源: 互联网

标签:springboot Tomcat request authentication private token session debug


本文介绍springboot项目采用spring-security认证,传递token,session的生成流程,分析源码创建过程。

最主要的入口在org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationProcessingFilter#doFilter

这个请求过滤器中。具体访问流程如下

Tomcat接收请求进入org.apache.catalina.authenticator.AuthenticatorBase#invoke这个方法。

流程进入下一个过滤器:

org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationProcessingFilter#doFilter

public class OAuth2AuthenticationProcessingFilter implements Filter, InitializingBean {
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException,
			ServletException {

		final boolean debug = logger.isDebugEnabled();
		final HttpServletRequest request = (HttpServletRequest) req;
		final HttpServletResponse response = (HttpServletResponse) res;

		try {
// 提取token值封装到PreAuthenticatedAuthenticationToken类中
			Authentication authentication = tokenExtractor.extract(request);
			
			if (authentication == null) {
//isAuthenticated()是否认证通过
				if (stateless && isAuthenticated()) {
					if (debug) {
						logger.debug("Clearing security context.");
					}
//    清除context
					SecurityContextHolder.clearContext();
				}
				if (debug) {
					logger.debug("No token in request, will continue chain.");
				}
			}
			else {
//设置request属性,token值
				request.setAttribute(OAuth2AuthenticationDetails.ACCESS_TOKEN_VALUE, authentication.getPrincipal());
				if (authentication instanceof AbstractAuthenticationToken) {
					AbstractAuthenticationToken needsDetails = (AbstractAuthenticationToken) authentication;
					needsDetails.setDetails(authenticationDetailsSource.buildDetails(request));
				}
// 去调用 用户服务认证token信息。返回认证结果
				Authentication authResult = authenticationManager.authenticate(authentication);

				if (debug) {
					logger.debug("Authentication success: " + authResult);
				}
//发布认证结果事件
				eventPublisher.publishAuthenticationSuccess(authResult);
				SecurityContextHolder.getContext().setAuthentication(authResult);

			}
		}
		catch (OAuth2Exception failed) {
			SecurityContextHolder.clearContext();

			if (debug) {
				logger.debug("Authentication request failed: " + failed);
			}
			eventPublisher.publishAuthenticationFailure(new BadCredentialsException(failed.getMessage(), failed),
					new PreAuthenticatedAuthenticationToken("access-token", "N/A"));

			authenticationEntryPoint.commence(request, response,
					new InsufficientAuthenticationException(failed.getMessage(), failed));

			return;
		}

		chain.doFilter(request, response);
	}
}

再进入org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationManager#authenticate

 

public class OAuth2AuthenticationManager implements AuthenticationManager, InitializingBean {
	public Authentication authenticate(Authentication authentication) throws AuthenticationException {

		if (authentication == null) {
			throw new InvalidTokenException("Invalid token (token not found)");
		}
		String token = (String) authentication.getPrincipal();
// 访问认证服务,返回认证用户信息
		OAuth2Authentication auth = tokenServices.loadAuthentication(token);
		if (auth == null) {
			throw new InvalidTokenException("Invalid token: " + token);
		}

		Collection<String> resourceIds = auth.getOAuth2Request().getResourceIds();
		if (resourceId != null && resourceIds != null && !resourceIds.isEmpty() && !resourceIds.contains(resourceId)) {
			throw new OAuth2AccessDeniedException("Invalid token does not contain resource id (" + resourceId + ")");
		}

		checkClientDetails(auth);

		if (authentication.getDetails() instanceof OAuth2AuthenticationDetails) {
			OAuth2AuthenticationDetails details = (OAuth2AuthenticationDetails) authentication.getDetails();
			// Guard against a cached copy of the same details
			if (!details.equals(auth.getDetails())) {
				// Preserve the authentication details from the one loaded by token services
				details.setDecodedDetails(auth.getDetails());
			}
		}
		auth.setDetails(authentication.getDetails());
//设置认证成功true
		auth.setAuthenticated(true);
		return auth;

	}
}

 

 上边2张图是认证失败的,token过期了,

再次获取token。

认证成功后进入org.springframework.security.web.session.SessionManagementFilter#doFilter

这个类是管理session的

public class SessionManagementFilter extends GenericFilterBean {
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
			throws IOException, ServletException {
		HttpServletRequest request = (HttpServletRequest) req;
		HttpServletResponse response = (HttpServletResponse) res;

		if (request.getAttribute(FILTER_APPLIED) != null) {
			chain.doFilter(request, response);
			return;
		}

		request.setAttribute(FILTER_APPLIED, Boolean.TRUE);

		if (!securityContextRepository.containsContext(request)) {
//获取上次认证成功返回的信息,这里存入了ThreadLocal中
			Authentication authentication = SecurityContextHolder.getContext()
					.getAuthentication();

			if (authentication != null && !trustResolver.isAnonymous(authentication)) {
				// The user has been authenticated during the current request, so call the
				// session strategy
				try {
//执行session管理策略,配置在
//org.springframework.security.config.annotation.web.configurers.SessionManagementConfigurer这个类中
					sessionAuthenticationStrategy.onAuthentication(authentication,
							request, response);
				}
				catch (SessionAuthenticationException e) {
					// The session strategy can reject the authentication
					logger.debug(
							"SessionAuthenticationStrategy rejected the authentication object",
							e);
					SecurityContextHolder.clearContext();
					failureHandler.onAuthenticationFailure(request, response, e);

					return;
				}
				// Eagerly save the security context to make it available for any possible
				// re-entrant
				// requests which may occur before the current request completes.
				// SEC-1396.
				securityContextRepository.saveContext(SecurityContextHolder.getContext(),
						request, response);
			}
			else {
				// No security context or authentication present. Check for a session
				// timeout
				if (request.getRequestedSessionId() != null
						&& !request.isRequestedSessionIdValid()) {
					if (logger.isDebugEnabled()) {
						logger.debug("Requested session ID "
								+ request.getRequestedSessionId() + " is invalid.");
					}

					if (invalidSessionStrategy != null) {
						invalidSessionStrategy
								.onInvalidSessionDetected(request, response);
						return;
					}
				}
			}
		}

		chain.doFilter(request, response);
	}
}

首先进入session的组合管理策略,在进入自己配置的 

org.springframework.security.web.authentication.session.CompositeSessionAuthenticationStrategy#onAuthentication

     再进入org.springframework.web.servlet.DispatcherServlet#doService

session的生成类org.apache.catalina.util.StandardSessionIdGenerator

session配置类

public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
		extends AbstractHttpConfigurer<SessionManagementConfigurer<H>, H> {
	private final SessionAuthenticationStrategy DEFAULT_SESSION_FIXATION_STRATEGY = createDefaultSessionFixationProtectionStrategy();
//默认的session策略是ChangeSessionIdAuthenticationStrategy,每次都会生成一个新的
	private SessionAuthenticationStrategy sessionFixationAuthenticationStrategy = this.DEFAULT_SESSION_FIXATION_STRATEGY;
	private SessionAuthenticationStrategy sessionAuthenticationStrategy;
	private SessionAuthenticationStrategy providedSessionAuthenticationStrategy;
//失效session策略
	private InvalidSessionStrategy invalidSessionStrategy;
	private SessionInformationExpiredStrategy expiredSessionStrategy;
	private List<SessionAuthenticationStrategy> sessionAuthenticationStrategies = new ArrayList<>();
	private SessionRegistry sessionRegistry;
//允许的最大session数量
	private Integer maximumSessions;
	private String expiredUrl;
	private boolean maxSessionsPreventsLogin;
	private SessionCreationPolicy sessionPolicy = SessionCreationPolicy.IF_REQUIRED;
	private boolean enableSessionUrlRewriting;
//session失效需要跳转地址
	private String invalidSessionUrl;
	private String sessionAuthenticationErrorUrl;
	private AuthenticationFailureHandler sessionAuthenticationFailureHandler;
}

标签:springboot,Tomcat,request,authentication,private,token,session,debug
来源: https://blog.csdn.net/wangfenglei123456/article/details/122556736

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有