前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Springsecurity之LogoutFilter

Springsecurity之LogoutFilter

作者头像
克虏伯
发布2019-04-15 10:21:56
1.1K0
发布2019-04-15 10:21:56
举报

    注:Springsecurity版本4.3.x.RELEASE

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

                                                               图1     

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

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

List-1

代码语言:javascript
复制
public class LogoutFilter extends GenericFilterBean {
	private RequestMatcher logoutRequestMatcher;
	private final LogoutHandler handler;
	private final LogoutSuccessHandler logoutSuccessHandler;

	/**
	 * Constructor which takes a <tt>LogoutSuccessHandler</tt> instance to determine the
	 * target destination after logging out. The list of <tt>LogoutHandler</tt>s 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

代码语言:javascript
复制
<bean id="requestSingleLogoutFilter" class="org.springframework.security.web.authentication.logout.LogoutFilter">
	<constructor-arg value="https://localhost:9443/cas/logout"/>
	<constructor-arg>
		<bean class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler"/>
	</constructor-arg>
	<property name="filterProcessesUrl" value="/logout/cas"/>
</bean>

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

List-3

代码语言:javascript
复制
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

代码语言:javascript
复制
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方法。

                                                                图2

List-5

代码语言:javascript
复制
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

代码语言:javascript
复制
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

代码语言:javascript
复制
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);
}

(adsbygoogle = window.adsbygoogle || []).push({});

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018/11/12 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档