Spring Security Web 5.1.2 源码解析 — SecurityContextHolderAwareRequestFilter

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

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

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

概述

SecurityContextHolderAwareRequestFilter对请求HttpServletRequest采用Wrapper/Decorator模式包装成一个可以访问SecurityContextHolder中安全上下文的SecurityContextHolderAwareRequestWrapper。这样接口HttpServletRequest上定义的getUserPrincipal这种安全相关的方法才能访问到相应的安全信息。

针对Servlet 2.5Servlet 3,该过滤器使用了不一样的工厂,但最终都是使用SecurityContextHolderAwareRequestWrapper封装请求使其具备访问SecurityContextHolder安全上下文的能力。

源代码解析

    package org.springframework.security.web.servletapi;

    import java.io.IOException;
    import java.util.List;

    import javax.servlet.AsyncContext;
    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.authentication.AuthenticationManager;
    import org.springframework.security.authentication.AuthenticationTrustResolver;
    import org.springframework.security.authentication.AuthenticationTrustResolverImpl;
    import org.springframework.security.core.context.SecurityContext;
    import org.springframework.security.core.context.SecurityContextHolder;
    import org.springframework.security.web.AuthenticationEntryPoint;
    import org.springframework.security.web.authentication.logout.LogoutHandler;
    import org.springframework.util.Assert;
    import org.springframework.util.ClassUtils;
    import org.springframework.web.filter.GenericFilterBean;

    public class SecurityContextHolderAwareRequestFilter extends GenericFilterBean {
        // ~ Instance fields
        // ====================================================================================

        // 缺省角色名称的前缀
        private String rolePrefix = "ROLE_";

        // 用于封装HttpServletRequest的工厂类,最终目的是封装HttpServletRequest
        // 使之具有访问SecurityContextHolder中安全上下文的能力。
        // 针对 Servlet 2.5 和 Servlet 3 使用的不同实现类。
        private HttpServletRequestFactory requestFactory;

        private AuthenticationEntryPoint authenticationEntryPoint;

        private AuthenticationManager authenticationManager;

        private List<LogoutHandler> logoutHandlers;

        // 判断认证对象Authentication是何种类型:是否匿名Authentication,
        // 是否 Remember Me Authentication。
        // 缺省使用实现AuthenticationTrustResolverImpl,
        // 根据对象Authentication所使用的实现类是AnonymousAuthenticationToken
        // 还是RememberMeAuthenticationToken达到上述目的
        private AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl();

        // ~ Methods
        // ====================================================================================
        // 指定角色前缀,
        public void setRolePrefix(String rolePrefix) {
            Assert.notNull(rolePrefix, "Role prefix must not be null");
            this.rolePrefix = rolePrefix;
            // 角色前缀变更时更新requestFactory工厂
            updateFactory();
        }

        /** * * Sets the AuthenticationEntryPoint used when integrating * HttpServletRequest with Servlet 3 APIs. Specifically, it will be used when * HttpServletRequest#authenticate(HttpServletResponse) is called and the user * is not authenticated. * * * If the value is null (default), then the default container behavior will be be * retained when invoking HttpServletRequest#authenticate(HttpServletResponse) * . * * * @param authenticationEntryPoint the AuthenticationEntryPoint to use when * invoking HttpServletRequest#authenticate(HttpServletResponse) if the user * is not authenticated. * * @throws IllegalStateException if the Servlet 3 APIs are not found on the classpath */
        public void setAuthenticationEntryPoint(
                AuthenticationEntryPoint authenticationEntryPoint) {
            this.authenticationEntryPoint = authenticationEntryPoint;
        }

        /** * * Sets the AuthenticationManager used when integrating * HttpServletRequest with Servlet 3 APIs. Specifically, it will be used when * HttpServletRequest#login(String, String) is invoked to determine if the * user is authenticated. * * * If the value is null (default), then the default container behavior will be * retained when invoking HttpServletRequest#login(String, String). * * * @param authenticationManager the AuthenticationManager to use when invoking * HttpServletRequest#login(String, String) * * @throws IllegalStateException if the Servlet 3 APIs are not found on the classpath */
        public void setAuthenticationManager(AuthenticationManager authenticationManager) {
            this.authenticationManager = authenticationManager;
        }

        /** * * Sets the LogoutHandlers used when integrating with * HttpServletRequest with Servlet 3 APIs. Specifically it will be used when * HttpServletRequest#logout() is invoked in order to log the user out. So * long as the LogoutHandlers do not commit the HttpServletResponse * (expected), then the user is in charge of handling the response. * * * If the value is null (default), the default container behavior will be retained * when invoking HttpServletRequest#logout(). * * * @param logoutHandlers the Lis<LogoutHandler> when invoking * HttpServletRequest#logout(). * * @throws IllegalStateException if the Servlet 3 APIs are not found on the classpath */
        public void setLogoutHandlers(List<LogoutHandler> logoutHandlers) {
            this.logoutHandlers = logoutHandlers;
        }

        public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
                throws IOException, ServletException {
            chain.doFilter(this.requestFactory.create((HttpServletRequest) req,
                    (HttpServletResponse) res), res);
        }

        @Override
        public void afterPropertiesSet() throws ServletException {
        // 本Filter因为继承自GenericFilterBean,从而隐含地实现了接口InitializingBean,
        // 所以会有此方法。而此方法会在该Filter bean被初始化时调用。此时会确定具体使用的
        // requestFactory 实例
            super.afterPropertiesSet();
            updateFactory();
        }

        private void updateFactory() {
            // 更新封装HttpServletRequest的工厂实例requestFactory,
            // 根据当前使用的Servlet版本的不同使用不同的工厂类
            String rolePrefix = this.rolePrefix;
            this.requestFactory = isServlet3() ? createServlet3Factory(rolePrefix)
                    : new HttpServlet25RequestFactory(this.trustResolver, rolePrefix);
        }

        /** * Sets the AuthenticationTrustResolver to be used. The default is * AuthenticationTrustResolverImpl. * * @param trustResolver the AuthenticationTrustResolver to use. Cannot be * null. */
        public void setTrustResolver(AuthenticationTrustResolver trustResolver) {
            Assert.notNull(trustResolver, "trustResolver cannot be null");
            this.trustResolver = trustResolver;
            // trustResolver 变更时更新requestFactory工厂
            updateFactory();
        }

        private HttpServletRequestFactory createServlet3Factory(String rolePrefix) {
            HttpServlet3RequestFactory factory = new HttpServlet3RequestFactory(rolePrefix);
            factory.setTrustResolver(this.trustResolver);
            factory.setAuthenticationEntryPoint(this.authenticationEntryPoint);
            factory.setAuthenticationManager(this.authenticationManager);
            factory.setLogoutHandlers(this.logoutHandlers);
            return factory;
        }

        /** * Returns true if the Servlet 3 APIs are detected. * @return */
        private boolean isServlet3() {
            return ClassUtils.hasMethod(ServletRequest.class, "startAsync");
        }
    }

其他文章

Spring Security Web 5.1.2 源码解析 – 安全相关Filter清单


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

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

评论 抢沙发

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

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

支付宝扫一扫打赏

微信扫一扫打赏