Springsecurity之LogoutFilter

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

    注:Springsecurity版本4.3.x.RELEASE

    先上一张LogoutFilter的类继承图,如下图1所示,原图见我的Github。

Springsecurity之LogoutFilter_第1张图片

                                                               图1     

    LogoutFilter和其它Springsecurity的Filter一样,都是继承自GenericFilterBean。

    来看下LogoutFilter的属性和构造方法,如下List-1所示。当我们定义了如List-2所示的bean时,调用的是List-1中的第二个构造方法。

    List-1

public class LogoutFilter extends GenericFilterBean {
	private RequestMatcher logoutRequestMatcher;
	private final LogoutHandler handler;
	private final LogoutSuccessHandler logoutSuccessHandler;

	/**
	 * Constructor which takes a LogoutSuccessHandler instance to determine the
	 * target destination after logging out. The list of LogoutHandlers are
	 * intended to perform the actual logout functionality (such as clearing the security
	 * context, invalidating the session, etc.).
	 */
	public LogoutFilter(LogoutSuccessHandler logoutSuccessHandler,
			LogoutHandler... handlers) {
		this.handler = new CompositeLogoutHandler(handlers);
		Assert.notNull(logoutSuccessHandler, "logoutSuccessHandler cannot be null");
		this.logoutSuccessHandler = logoutSuccessHandler;
		setFilterProcessesUrl("/logout");
	}

	public LogoutFilter(String logoutSuccessUrl, LogoutHandler... handlers) {
		this.handler = new CompositeLogoutHandler(handlers);
		Assert.isTrue(
				!StringUtils.hasLength(logoutSuccessUrl)
						|| UrlUtils.isValidRedirectUrl(logoutSuccessUrl),
				() -> logoutSuccessUrl + " isn't a valid redirect URL");
		SimpleUrlLogoutSuccessHandler urlLogoutSuccessHandler = new SimpleUrlLogoutSuccessHandler();
		if (StringUtils.hasText(logoutSuccessUrl)) {
			urlLogoutSuccessHandler.setDefaultTargetUrl(logoutSuccessUrl);
		}
		logoutSuccessHandler = urlLogoutSuccessHandler;
		setFilterProcessesUrl("/logout");
	}

    List-2


	
	
		
	
	

    来看下LogoutFilter的doFilter方法,如下List-3所示,

    List-3

public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
	HttpServletRequest request = (HttpServletRequest) req;
	HttpServletResponse response = (HttpServletResponse) res;
	if (requiresLogout(request, response)) {
		Authentication auth = SecurityContextHolder.getContext().getAuthentication();
		if (logger.isDebugEnabled()) {
			logger.debug("Logging out user '" + auth + "' and transferring to logout destination");
		}
		this.handler.logout(request, response, auth);
		logoutSuccessHandler.onLogoutSuccess(request, response, auth);
		return;
	}
	chain.doFilter(request, response);
}

     在List-3中:

  1. requiresLogout方法判断requst中的url是否是/logout/cas,见List-2中的属性filterProcessesUrl
  2. 如果满足步骤1的要求,那么调用LogoutHandler的logout方法,会将Session失效,此外将SecurityContextHolder清空
  3. 如果满足步骤1的要求,那么调用LogoutSuccessHandler的onLogoutSuccess方法,设置HttpServletResponse的重定向
  4. 如果满足步骤1的要求,那么不会调用FilterChain了

    来看下SecurityContextLogoutHandler的logout方法,如下List-4所示,

    List-4

public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
	Assert.notNull(request, "HttpServletRequest required");
	if (invalidateHttpSession) {
		HttpSession session = request.getSession(false);
		if (session != null) {
			logger.debug("Invalidating session: " + session.getId());
			session.invalidate();
		}
	}
	if (clearAuthentication) {
		SecurityContext context = SecurityContextHolder.getContext();
		context.setAuthentication(null);
	}
	SecurityContextHolder.clearContext();
}

    在List-4中:

  1. 会将HttpSession失效
  2. 清空SecurityContextHolder的context

    来看下SimpleUrlLogoutSuccessHandler,如图2和List-5所示,它直接调用父类AbstractAuthenticationTargetUrlRequestHandler的handle方法,看List-6所示,方法determineTargetUrl决定使用哪个targetUrl;List-6中handle方法的redirectStrategy.sendRedirect(request, response, targetUrl),调用的DefaultRedirectStrategy的sendRedirect方法,如List-7所示,最终调用的是response的sendRedirect方法。

                    Springsecurity之LogoutFilter_第2张图片

                                                                图2

    List-5

public class SimpleUrlLogoutSuccessHandler extends
		AbstractAuthenticationTargetUrlRequestHandler implements LogoutSuccessHandler {

	public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response,
			Authentication authentication) throws IOException, ServletException {
		super.handle(request, response, authentication);
	}
}

    List-6

protected void handle(HttpServletRequest request, HttpServletResponse response,
		Authentication authentication) throws IOException, ServletException {
	String targetUrl = determineTargetUrl(request, response);
	if (response.isCommitted()) {
		logger.debug("Response has already been committed. Unable to redirect to "
				+ targetUrl);
		return;
	}
	redirectStrategy.sendRedirect(request, response, targetUrl);
}

/**
 * Builds the target URL according to the logic defined in the main class Javadoc.
 */
protected String determineTargetUrl(HttpServletRequest request,
		HttpServletResponse response) {
	if (isAlwaysUseDefaultTargetUrl()) {
		return defaultTargetUrl;
	}
	// Check for the parameter and use that if available
	String targetUrl = null;
	if (targetUrlParameter != null) {
		targetUrl = request.getParameter(targetUrlParameter);
		if (StringUtils.hasText(targetUrl)) {
			logger.debug("Found targetUrlParameter in request: " + targetUrl);
			return targetUrl;
		}
	}
	if (useReferer && !StringUtils.hasLength(targetUrl)) {
		targetUrl = request.getHeader("Referer");
		logger.debug("Using Referer header: " + targetUrl);
	}
	if (!StringUtils.hasText(targetUrl)) {
		targetUrl = defaultTargetUrl;
		logger.debug("Using default Url: " + targetUrl);
	}
	return targetUrl;
}

    List-7

public void sendRedirect(HttpServletRequest request, HttpServletResponse response,
		String url) throws IOException {
	String redirectUrl = calculateRedirectUrl(request.getContextPath(), url);
	redirectUrl = response.encodeRedirectURL(redirectUrl);

	if (logger.isDebugEnabled()) {
		logger.debug("Redirecting to '" + redirectUrl + "'");
	}

	response.sendRedirect(redirectUrl);
}

 

转载于:https://my.oschina.net/u/2518341/blog/2875229

你可能感兴趣的:(Springsecurity之LogoutFilter)