spring security 4 filter SecurityContextPersistenceFilter(三)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_18416057/article/details/88082336

今天我们讲的filter是SecurityContextPersistenceFilter,通过其名字,就能大概猜出来这个过滤器的作用,就是用来持久化SecurityContext实例用的,也是spring security filter 核心的过滤器之一。

      接下去我们将根据其源码分析一下其作用,先看看doFilter这个方法

public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest)req;
        HttpServletResponse response = (HttpServletResponse)res;
        if (request.getAttribute("__spring_security_scpf_applied") != null) {
            chain.doFilter(request, response);
        } else {
            boolean debug = this.logger.isDebugEnabled();
            request.setAttribute("__spring_security_scpf_applied", Boolean.TRUE);
            if (this.forceEagerSessionCreation) {
                HttpSession session = request.getSession();
                if (debug && session.isNew()) {
                    this.logger.debug("Eagerly created session: " + session.getId());
                }
            }

            HttpRequestResponseHolder holder = new HttpRequestResponseHolder(request, response);
            SecurityContext contextBeforeChainExecution = this.repo.loadContext(holder);
            boolean var13 = false;

            try {
 // //请求开始时,设置安全上下文信息,这样就避免了用户直接从Session中获取安全上下文信息
                var13 = true;
                SecurityContextHolder.setContext(contextBeforeChainExecution);
                chain.doFilter(holder.getRequest(), holder.getResponse());
                var13 = false;
            } finally {
        // 过滤器走完之类就清楚SecurityContextHolder中的SecurityContext 对象
                if (var13) {
                    SecurityContext contextAfterChainExecution = SecurityContextHolder.getContext();
                    SecurityContextHolder.clearContext();
                    this.repo.saveContext(contextAfterChainExecution, holder.getRequest(), holder.getResponse());
                    request.removeAttribute("__spring_security_scpf_applied");
                    if (debug) {
                        this.logger.debug("SecurityContextHolder now cleared, as request processing completed");
                    }

                }
            }

            SecurityContext contextAfterChainExecution = SecurityContextHolder.getContext();
            SecurityContextHolder.clearContext();
            this.repo.saveContext(contextAfterChainExecution, holder.getRequest(), holder.getResponse());
            request.removeAttribute("__spring_security_scpf_applied");
            if (debug) {
                this.logger.debug("SecurityContextHolder now cleared, as request processing completed");
            }

        }
    }

我们先来看一下核心代码

 // 将request,response对象封装到  HttpRequestResponseHolder 里
 HttpRequestResponseHolder holder = new HttpRequestResponseHolder(request, response);
// 从SecurityContextRepository对象中获取SecurityContext 
            SecurityContext contextBeforeChainExecution = this.repo.loadContext(holder);

然后我们看一下SecurityContextRepository接口的实现类HttpSessionSecurityContextRepository的loadContext方法
 


    public SecurityContext loadContext(HttpRequestResponseHolder requestResponseHolder) {
        HttpServletRequest request = requestResponseHolder.getRequest();
        HttpServletResponse response = requestResponseHolder.getResponse();
        HttpSession httpSession = request.getSession(false);
   //  根据特定的key从session中获取SecurityContext
        SecurityContext context = this.readSecurityContextFromSession(httpSession);
        if (context == null) {
            if (this.logger.isDebugEnabled()) {
                this.logger.debug("No SecurityContext was available from the HttpSession: " + httpSession + ". A new one will be created.");
            }
         //  如果session里面没有就重新生成一个SecurityContext 

            context = this.generateNewContext();
        }

        
        HttpSessionSecurityContextRepository.SaveToSessionResponseWrapper wrappedResponse = new HttpSessionSecurityContextRepository.SaveToSessionResponseWrapper(response, request, httpSession != null, context);
        requestResponseHolder.setResponse(wrappedResponse);
        if (this.isServlet3) {
            requestResponseHolder.setRequest(new HttpSessionSecurityContextRepository.Servlet3SaveToSessionRequestWrapper(request, wrappedResponse));
        }

        return context;
    }

然后我们先来看看这个方法里面的readSecurityContextFromSession方法

private SecurityContext readSecurityContextFromSession(HttpSession httpSession) {
        boolean debug = this.logger.isDebugEnabled();
        if (httpSession == null) {
            if (debug) {
                this.logger.debug("No HttpSession currently exists");
            }

            return null;
        } else {
            Object contextFromSession = httpSession.getAttribute(this.springSecurityContextKey);
            if (contextFromSession == null) {
                if (debug) {
                    this.logger.debug("HttpSession returned null object for SPRING_SECURITY_CONTEXT");
                }

                return null;
            } else if (!(contextFromSession instanceof SecurityContext)) {
                if (this.logger.isWarnEnabled()) {
                    this.logger.warn(this.springSecurityContextKey + " did not contain a SecurityContext but contained: '" + contextFromSession + "'; are you improperly modifying the HttpSession directly (you should always use SecurityContextHolder) or using the HttpSession attribute reserved for this class?");
                }

                return null;
            } else {
                if (debug) {
                    this.logger.debug("Obtained a valid SecurityContext from " + this.springSecurityContextKey + ": '" + contextFromSession + "'");
                }

                return (SecurityContext)contextFromSession;
            }
        }
    }

从代码上看这个方法就是从session中根据springSecurityContextKey获取SecurityContext对象,没有就直接new一个,然后set到SecurityContextHolder里面,请求执行完了之后调用SecurityContextHolder.clearContext()清除

总结:

两个主要职责:请求来临时,创建SecurityContext放到SecurityContextHolder里,请求结束时清空SecurityContextHolder的SecurityContext。

流程:从session中获取SecurityContext,然后放到上下文中,之后的filter大多依赖这个来获取登录态。其主要是通过HttpSessionSecurityContextRepository来存取的,请求结束之后清除SecurityContext

猜你喜欢

转载自blog.csdn.net/qq_18416057/article/details/88082336
今日推荐