Spring Security Web 5.1.2 源码解析 — LogoutFilter

扫码关注公众号:Java 技术驿站

发送:vip
将链接复制到本浏览器,永久解锁本站全部文章

【公众号:Java 技术驿站】 【加作者微信交流技术,拉技术群】
免费领取10G资料包与项目实战视频资料

概述

在进行安全配置时,不管是明确指定还是使用缺省配置,最终安全配置中都会包含以下退出登录配置信息:

  • 怎样的请求是一个退出登录请求

    • 这里包含两部分信息: url, http method
  • 成功退出登录过程需要做哪些事情

    • 也就是各种配置的LogoutHandler
    • 核心LogoutHandler:SecurityContextLogoutHandler–销毁sessionSecurityContextHolder内容
  • 成功退出登录后跳转到哪里

    • 也就是配置中的 logoutSuccessUrl

基于以上配置信息,LogoutFilter被设计用于检测用户退出登录请求,执行相应的处理工作以及退出登录后的页面跳转。

源代码解析

    package org.springframework.security.web.authentication.logout;

    import java.io.IOException;

    import javax.servlet.FilterChain;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;

    import org.springframework.security.core.Authentication;
    import org.springframework.security.core.context.SecurityContextHolder;
    import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
    import org.springframework.security.web.util.matcher.RequestMatcher;
    import org.springframework.security.web.util.UrlUtils;
    import org.springframework.util.Assert;
    import org.springframework.util.StringUtils;
    import org.springframework.web.filter.GenericFilterBean;

    public class LogoutFilter extends GenericFilterBean {

        // ~ Instance fields
        // ================================================================================================

        private RequestMatcher logoutRequestMatcher;

        private final LogoutHandler handler;
        private final LogoutSuccessHandler logoutSuccessHandler;

        // ~ Constructors
        // ===================================================================================================

        /** * 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.). * 缺省情况下,这里的LogoutSuccessHandler是一个SimpleUrlLogoutSuccessHandler实例, * 在退出登录成功时跳转到/。 * * 安全配置信息中还会包含对cookie,remember me 等安全机制的配置,这些机制中在用户成功退出 * 登录时也会执行一些相应的清场工作,这些工作就是通过参数handlers传递进来的。这些handlers * 中最核心的一个就是SecurityContextLogoutHandler,它会销毁session和针对当前请求的 * SecurityContextHolder中的安全上下文对象,这是真正意义上的退出登录。 */
        public LogoutFilter(LogoutSuccessHandler logoutSuccessHandler,
                LogoutHandler... handlers) {
            this.handler = new CompositeLogoutHandler(handlers);
            Assert.notNull(logoutSuccessHandler, "logoutSuccessHandler cannot be null");
            this.logoutSuccessHandler = logoutSuccessHandler;
            // 定义一个缺省的用户退出登录请求匹配器:
            // 只要用户请求/logout而无论http method是什么,都认为是要退出登录了,
            // 该缺省值通常会被安全配置覆盖,请留意
            setFilterProcessesUrl("/logout");
        }

        // 另外一个构造函数,如果没有指定logoutSuccessHandler,而是只指定了logoutSuccessUrl,
        // 该方法会根据logoutSuccessUrl构造一个logoutSuccessHandler:SimpleUrlLogoutSuccessHandler
        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");
        }

        // ~ Methods
        // ========================================================================================================

        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是一个SimpleUrlLogoutSuccessHandler实例,
                // 在退出登录成功时跳转到/。
                // 上面已经成功退出了用户登录,现在跳转到相应的页面
                logoutSuccessHandler.onLogoutSuccess(request, response, auth);

                // 注意,这里完成了用户退出登录动作和页面跳转,所以当前请求的处理任务已经结束,
                // 也就是说不用再继续filter chain的执行了,直接函数返回即可。
                return;
            }

            // 不是用户请求退出登录的情况,继续执行 filter chain 。
            chain.doFilter(request, response);
        }

        /** * Allow subclasses to modify when a logout should take place. * 根据当前请求和安全配置检测是否用户在请求退出登录,如果是用户在请求退出登录的情况返回true, * 否则返回false * @param request the request * @param response the response * * @return true if logout should occur, false otherwise */
        protected boolean requiresLogout(HttpServletRequest request,
                HttpServletResponse response) {
            // logoutRequestMatcher 是配置时明确指定的,或者是根据其他配置计算出来的
            return logoutRequestMatcher.matches(request);
        }

        // 配置阶段会将用户明确指定的logoutRequestMatcher或者根据其他配置计算出来的logoutRequestMatcher
        // 通过该方法设置到当前Filter对象
        public void setLogoutRequestMatcher(RequestMatcher logoutRequestMatcher) {
            Assert.notNull(logoutRequestMatcher, "logoutRequestMatcher cannot be null");
            this.logoutRequestMatcher = logoutRequestMatcher;
        }

        // 调用该方法则会将当前Filter的logoutRequestMatcher设置为一个根据filterProcessesUrl计算出来的
        //AntPathRequestMatcher,该matcher会仅根据请求url进行匹配,而不管http method是什么
        //
        // 在该Filter的构造函数中就调用了该方法setFilterProcessesUrl("/logout"),从而构建了一个缺省的
        // AntPathRequestMatcher,表示只要用户访问 url /logout,不管http method是什么,都认为用户想要
        // 退出登录。但实际上,该初始值都会被配置过程中根据用户配置信息计算出的AntPathRequestMatcher
        // 调用上面的setLogoutRequestMatcher(logoutRequestMatcher)覆盖该matcher 
        public void setFilterProcessesUrl(String filterProcessesUrl) {
            this.logoutRequestMatcher = new AntPathRequestMatcher(filterProcessesUrl);
        }
    }

参考文章


来源:http://ddrv.cn/a/88268

赞(0) 打赏
版权归原创作者所有,任何形式的转载请联系博主:daming_90:Java 技术驿站 » Spring Security Web 5.1.2 源码解析 — LogoutFilter

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏