美文网首页权限安全加密
Spring Security源码一:Spring Securi

Spring Security源码一:Spring Securi

作者: wencai | 来源:发表于2018-08-01 17:21 被阅读61次

一、Spring Security是什么

  Spring Security为J2EE企业级应用提供了全面的安全服务。应用级别的安全主要分为“验证( authentication) ”和“(授权) authorization ”两个部分。

  • Authentication:指的是建立规则( principal )的过程。规则可以是一个用户、设备、或者其他可以在我们的应用中执行某种操作的其他系统。
  • Authorization:指的是判断某个 principal 在我们的应用是否允许执行某个操作。在 进行授权判断之前,要求其所要使用到的规则必须在验证过程中已经建立好了。
      在验证(Authentication )层面, Spring Security 提供了不同的验证模型。大部分的authentication模型来自于第三方或者权威机构或者由一些相关的标准制定组织(如IETF)开发。此外,Spring Security也提供了一些验证特性。
      除了验证机制, Spring Security 也提供了一系列的授权能力。主要感兴趣的是以下三个方面:
  • 对web请求进行授权
  • 授权某个方法是否可以被调用
  • 授权访问单个领域对象实例

二、Spring Security如何拦截请求

用传统web.xml可以方便看到Spring Security的入口类

<filter>
   <filter-name>springSecurityFilterChain</filter-name>
  <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
   <filter-name>springSecurityFilterChain</filter-name>
   <url-pattern>/*</url-pattern>
</filter-mapping>

从spring容器中读取名称为springSecurityFilterChain的一个Filter实例,从而获取到对应代理的Filter。
然后在doFilter方法中调用该委托的filter,也就实现的拦截请求。

public class DelegatingFilterProxy extends GenericFilterBean {
      ……
      @Override
      public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {

        // Lazily initialize the delegate if necessary.
        Filter delegateToUse = this.delegate;
        if (delegateToUse == null) {
            synchronized (this.delegateMonitor) {
                delegateToUse = this.delegate;
                if (delegateToUse == null) {
                    WebApplicationContext wac = findWebApplicationContext();
                    if (wac == null) {
                        throw new IllegalStateException("No WebApplicationContext found: " +
                                "no ContextLoaderListener or DispatcherServlet registered?");
                    }
                    delegateToUse = initDelegate(wac);
                }
                this.delegate = delegateToUse;
            }
        }

        // Let the delegate perform the actual doFilter operation.
        invokeDelegate(delegateToUse, request, response, filterChain);
    }
    protected Filter initDelegate(WebApplicationContext wac) throws ServletException {
        String targetBeanName = getTargetBeanName();
        Assert.state(targetBeanName != null, "No target bean name set");
        Filter delegate = wac.getBean(targetBeanName, Filter.class);
        if (isTargetFilterLifecycle()) {
            delegate.init(getFilterConfig());
        }
        return delegate;
    }
    protected void invokeDelegate(
            Filter delegate, ServletRequest request, ServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {

        delegate.doFilter(request, response, filterChain);
    }
}

  在JavaConfig中是如何实现的呢?查看@EnableWebSecurity源码,发现引入了类WebSecurityConfiguration。源码如下:

    public static final String DEFAULT_FILTER_NAME = "springSecurityFilterChain";

    @Bean(name = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)
    public Filter springSecurityFilterChain() throws Exception {
        boolean hasConfigurers = webSecurityConfigurers != null
                && !webSecurityConfigurers.isEmpty();
        if (!hasConfigurers) {
            WebSecurityConfigurerAdapter adapter = objectObjectPostProcessor
                    .postProcess(new WebSecurityConfigurerAdapter() {
                    });
            webSecurity.apply(adapter);
        }
        return webSecurity.build();
    }

三、Spring Security拦截请求后如何处理

为了方便理解,先讲解下Filter和FilterChain的关系。参见:https://www.jianshu.com/p/76d7ae3bf398
  通过断点跟踪发现,DelegatingFilterProxy代理的是FilterChainProxy,继续看源码的doFilter及其涉及到的其他方法:


public class FilterChainProxy extends GenericFilterBean {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
        boolean clearContext = request.getAttribute(FILTER_APPLIED) == null;
        if (clearContext) {
            try {
                request.setAttribute(FILTER_APPLIED, Boolean.TRUE);
                doFilterInternal(request, response, chain);
            }
            finally {
                SecurityContextHolder.clearContext();
                request.removeAttribute(FILTER_APPLIED);
            }
        }
        else {
              //第一步:执行过滤任务
            doFilterInternal(request, response, chain);
        }
    }

    private void doFilterInternal(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {

        FirewalledRequest fwRequest = firewall
                .getFirewalledRequest((HttpServletRequest) request);
        HttpServletResponse fwResponse = firewall
                .getFirewalledResponse((HttpServletResponse) response);
        //第二步:获取filterChains中第一个满足条件的过滤器集合
        List<Filter> filters = getFilters(fwRequest);
        //如果未引入任何过滤器,则继续执行默认的过滤器链
        if (filters == null || filters.size() == 0) {
            if (logger.isDebugEnabled()) {
                logger.debug(UrlUtils.buildRequestUrl(fwRequest)
                        + (filters == null ? " has no matching filters"
                                : " has an empty filter list"));
            }

            fwRequest.reset();

            chain.doFilter(fwRequest, fwResponse);

            return;
        }
        //第三步:插入自定义过滤器:将过滤器链和跟这个请求匹配的过滤器集合传入,来执行过滤请求。
        VirtualFilterChain vfc = new VirtualFilterChain(fwRequest, chain, filters);
        vfc.doFilter(fwRequest, fwResponse);
    }

    /**
     * Returns the first filter chain matching the supplied URL.
     *
     * @param request the request to match
     * @return an ordered array of Filters defining the filter chain
     */
    private List<Filter> getFilters(HttpServletRequest request) {
        for (SecurityFilterChain chain : filterChains) {
            if (chain.matches(request)) {
                return chain.getFilters();
            }
        }

        return null;
    }

private static class VirtualFilterChain implements FilterChain {
        private final FilterChain originalChain;
          //自定义的过滤器集合
        private final List<Filter> additionalFilters;
        private final FirewalledRequest firewalledRequest;
        private final int size;
        private int currentPosition = 0;

        @Override
        public void doFilter(ServletRequest request, ServletResponse response)
                throws IOException, ServletException {
            if (currentPosition == size) {
                if (logger.isDebugEnabled()) {
                    logger.debug(UrlUtils.buildRequestUrl(firewalledRequest)
                            + " reached end of additional filter chain; proceeding with original chain");
                }
             //第五步:自定义的过滤器集合执行完毕后,继续执行原有的过滤器链
                // Deactivate path stripping as we exit the security filter chain
                this.firewalledRequest.reset();

                originalChain.doFilter(request, response);
            }
            else {
                currentPosition++;
                //第四步:执行自定义的过滤器集合
                Filter nextFilter = additionalFilters.get(currentPosition - 1);

                if (logger.isDebugEnabled()) {
                    logger.debug(UrlUtils.buildRequestUrl(firewalledRequest)
                            + " at position " + currentPosition + " of " + size
                            + " in additional filter chain; firing Filter: '"
                            + nextFilter.getClass().getSimpleName() + "'");
                }

                nextFilter.doFilter(request, response, this);
            }
        }
    }
}
//一套规则对应的过滤器集合
public interface SecurityFilterChain {

    boolean matches(HttpServletRequest request);

    List<Filter> getFilters();
}

目前为止,我们可大致总结出过滤器的执行流程图:

相关文章

网友评论

    本文标题:Spring Security源码一:Spring Securi

    本文链接:https://www.haomeiwen.com/subject/fwprvftx.html