`
Dead_knight
  • 浏览: 1193522 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
博客专栏
752c8642-b795-3fe6-946e-a4e845bffdec
Spring Securi...
浏览量:238125
33caa84e-18a6-3036-a82b-6e2106a4de63
clojure专题
浏览量:48019
E17ca077-44df-3816-a3fe-471c43f6e1e5
WebLogic11g
浏览量:235881
社区版块
存档分类
最新评论

Spring Security3源码分析-SecurityContextPersistenceFilter分析

 
阅读更多
通过观察Filter的名字,就能大概猜出来这个过滤器的作用,是的,持久化SecurityContext实例。这个过滤器位置是;
org.springframework.security.web.context.SecurityContextPersistenceFilter
废话不说,看源码
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
            throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;
        if (request.getAttribute(FILTER_APPLIED) != null) {
            // ensure that filter is only applied once per request
            chain.doFilter(request, response);
            return;
        }

        final boolean debug = logger.isDebugEnabled();

        request.setAttribute(FILTER_APPLIED, Boolean.TRUE);

        if (forceEagerSessionCreation) {
            HttpSession session = request.getSession();

            if (debug && session.isNew()) {
                logger.debug("Eagerly created session: " + session.getId());
            }
        }
        //将request、response对象交给HttpRequestResponseHolder维持
        HttpRequestResponseHolder holder = new HttpRequestResponseHolder(request, response);
        //通过SecurityContextRepository接口的实现类装载SecurityContext实例
        //HttpSessionSecurityContextRepository将产生SecurityContext实例的任务交给SecurityContextHolder.createEmptyContext()完成
        //SecurityContextHolder再根据策略模式的不同,
        //把任务再交给相应策略类完成SecurityContext的创建
        //如果没有配置策略名称,则默认为
        //ThreadLocalSecurityContextHolderStrategy,
        //该类直接通过new SecurityContextImpl()创建实例
        SecurityContext contextBeforeChainExecution = repo.loadContext(holder);

        try {
        	//将产生的SecurityContext再通过SecurityContextHolder->
          //ThreadLocalSecurityContextHolderStrategy设置到ThreadLocal中
            SecurityContextHolder.setContext(contextBeforeChainExecution);
            //继续把请求流向下一个过滤器执行
            chain.doFilter(holder.getRequest(), holder.getResponse());

        } finally {
        	//先从SecurityContextHolder获取SecurityContext实例
            SecurityContext contextAfterChainExecution = SecurityContextHolder.getContext();
            // Crucial removal of SecurityContextHolder contents - do this before anything else.
            //再把SecurityContext实例从SecurityContextHolder中清空
            SecurityContextHolder.clearContext();
            //将SecurityContext实例持久化到session中
            repo.saveContext(contextAfterChainExecution, holder.getRequest(), holder.getResponse());
            request.removeAttribute(FILTER_APPLIED);
            if (debug) {
                logger.debug("SecurityContextHolder now cleared, as request processing completed");
            }
        }
    }

通过源码中的注释,应该可以看出来,这个Filter的作用主要是创建一个空的SecurityContext(如果session中没有SecurityContext实例),然后持久化到session中。
接下来看看repo.loadContext(holder);代码:
    public SecurityContext loadContext(HttpRequestResponseHolder requestResponseHolder) {
        HttpServletRequest request = requestResponseHolder.getRequest();
        HttpServletResponse response = requestResponseHolder.getResponse();
        HttpSession httpSession = request.getSession(false);
        //从session中获取SecurityContext
         SecurityContext context = readSecurityContextFromSession(httpSession);
        //如果获取不到SecurityContext,新建一个空的SecurityContext实例
        if (context == null) {
            if (logger.isDebugEnabled()) {
                logger.debug("No SecurityContext was available from the HttpSession: " + httpSession +". " +
                        "A new one will be created.");
            }
            context = generateNewContext();

        }
        //这里需要注意一下,response装饰器类重新包装了response
        requestResponseHolder.setResponse(new SaveToSessionResponseWrapper(response, request,
                httpSession != null, context.hashCode()));

        return context;
    }

进一步分析generateNewContext方法
    SecurityContext generateNewContext() {
        SecurityContext context = null;
        //创建SecurityContext实例并返回
        if (securityContextClass == null) {
            context = SecurityContextHolder.createEmptyContext();

            return context;
        }

        try {
            context = securityContextClass.newInstance();
        } catch (Exception e) {
            ReflectionUtils.handleReflectionException(e);
        }
        return context;
    }

实际上,SecurityContextHolder类也是把创建SecurityContext任务交给具体的SecurityContextHolderStrategy实现类处理,SecurityContextHolder类有一个静态初始化过程
    static {
        initialize();
    }

…………
    private static void initialize() {
        if ((strategyName == null) || "".equals(strategyName)) {
            // Set default
            strategyName = MODE_THREADLOCAL;
        }
        //默认的SecurityContextHolderStrategy实现类为
         //ThreadLocalSecurityContextHolderStrategy
        if (strategyName.equals(MODE_THREADLOCAL)) {
            strategy = new ThreadLocalSecurityContextHolderStrategy();
        } else if (strategyName.equals(MODE_INHERITABLETHREADLOCAL)) {
            strategy = new InheritableThreadLocalSecurityContextHolderStrategy();
        } else if (strategyName.equals(MODE_GLOBAL)) {
            strategy = new GlobalSecurityContextHolderStrategy();
        } else {
            // Try to load a custom strategy
            try {
                Class<?> clazz = Class.forName(strategyName);
                Constructor<?> customStrategy = clazz.getConstructor();
                strategy = (SecurityContextHolderStrategy) customStrategy.newInstance();
            } catch (Exception ex) {
                ReflectionUtils.handleReflectionException(ex);
            }
        }

        initializeCount++;
    }

现在来看ThreadLocalSecurityContextHolderStrategy源码
final class ThreadLocalSecurityContextHolderStrategy implements SecurityContextHolderStrategy {
    //~ Static fields/initializers =====================================================================================

    private static final ThreadLocal<SecurityContext> contextHolder = new ThreadLocal<SecurityContext>();

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

    public void clearContext() {
        contextHolder.set(null);
    }

    public SecurityContext getContext() {
        SecurityContext ctx = contextHolder.get();

        if (ctx == null) {
            ctx = createEmptyContext();
            contextHolder.set(ctx);
        }

        return ctx;
    }

    public void setContext(SecurityContext context) {
        Assert.notNull(context, "Only non-null SecurityContext instances are permitted");
        contextHolder.set(context);
    }
    //直接new一个SecurityContextImpl对象,
     //SecurityContextImpl类实现SecurityContext接口
    public SecurityContext createEmptyContext() {
        return new SecurityContextImpl();
    }
}

分析到这里,整个过程也清楚了。不过在filter原路返回时,还需要保存这个SecurityContext实例到session中,并且通过SecurityContextHolder将ThreadLocalSecurityContextHolderStrategy中ThreadLocal维持的SecurityContext实例清空。
          //将SecurityContext实例持久化到session中
            repo.saveContext(contextAfterChainExecution, holder.getRequest(), holder.getResponse());


    public void saveContext(SecurityContext context, HttpServletRequest request, HttpServletResponse response) {
        //由于之前response装饰器类SaveToSessionResponseWrapper
        //重新装饰了response
        SaveContextOnUpdateOrErrorResponseWrapper responseWrapper = (SaveContextOnUpdateOrErrorResponseWrapper)response;
        // saveContext() might already be called by the response wrapper
        // if something in the chain called sendError() or sendRedirect(). This ensures we only call it
        // once per request.
        if (!responseWrapper.isContextSaved() ) {
            //SaveToSessionResponseWrapper保存SecurityContext实例
            responseWrapper.saveContext(context);
        }
    }

SaveToSessionResponseWrapper的saveContext方法源码:
        protected void saveContext(SecurityContext context) {
            // See SEC-776
            if (authenticationTrustResolver.isAnonymous(context.getAuthentication())) {
                if (logger.isDebugEnabled()) {
                    logger.debug("SecurityContext contents are anonymous - context will not be stored in HttpSession. ");
                }
                return;
            }

            HttpSession httpSession = request.getSession(false);

            if (httpSession == null) {
                httpSession = createNewSessionIfAllowed(context);
            }

            // If HttpSession exists, store current SecurityContextHolder contents but only if
            // the SecurityContext has actually changed (see JIRA SEC-37)
            if (httpSession != null && context.hashCode() != contextHashBeforeChainExecution) {
                //保存SecurityContext到session中
                httpSession.setAttribute(SPRING_SECURITY_CONTEXT_KEY, context);

                if (logger.isDebugEnabled()) {
                    logger.debug("SecurityContext stored to HttpSession: '" + context + "'");
                }
            }
        }
6
0
分享到:
评论

相关推荐

    Spring Security-3.0.1中文官方文档(翻译版)

    Spring Security-3.0.1 中文官方文档(翻译版) 这次发布的Spring Security-3.0.1 是一个bug fix 版,主要是对3.0 中存在的一些问题进 行修 正。文档中没有添加新功能的介绍,但是将之前拼写错误的一些类名进行...

    spring security 参考手册中文版

    3. Spring Security 4.2的新特性 27 3.1 Web改进 27 3.2配置改进 28 3.3杂项 28 4.样品和指南(从这里开始) 28 5. Java配置 29 5.1 Hello Web安全Java配置 29 5.1.1 AbstractSecurityWebApplicationInitializer 31 ...

    SpringSecurity 3.0.1.RELEASE.CHM

    1.1. Spring Security是什么? 1.2. 历史 1.3. 发行版本号 1.4. 获得Spring Security 1.4.1. 项目模块 1.4.1.1. Core - spring-security-core.jar 1.4.1.2. Web - spring-security-web.jar 1.4.1.3. Config -...

    Spring Security 中文教程.pdf

    1.1. Spring Security是什么? 1.2. 历史 1.3. 发行版本号 1.4. 获得Spring Security 1.4.1. 项目模块 1.4.1.1. Core - spring-security-core.jar 1.4.1.2. Web - spring-security-web.jar 1.4.1.3. ...

    security-parent

    1 = {SecurityContextPersistenceFilter @ 7760} 2 = {HeaderWriterFilter @ 7759} 3 = {CsrfFilter @ 7758} 4 = {LogoutFilter @ 7757} 5 = {UsernamePasswordAuthenticationFilter @ 7755} 6 = {...

    对接openai接口,采用现有的开源前端实现ai对话(Java)

    //开始进入 SecurityContextPersistenceFilter-&gt;doFilter方法 FilterSecurityInterceptor 中的doFilter-&gt;invoke方法 //看有没有权限 获取遍历 antMatchers中的url有的话标记为不用授权 AbstractSecurityInterceptor...

Global site tag (gtag.js) - Google Analytics