zoukankan      html  css  js  c++  java
  • ShiroFilterFactoryBean分析

    创建核心Filter

    同其他框架一样,都有个切入点,这个核心Filter就是拦截所有请求的。

    通过web.xml中配置的Filer进入,执行init方法获取这个instance,调用下面的createInstance方法创建核心Filter:

    protected AbstractShiroFilter createInstance() throws Exception {
    
        log.debug("Creating Shiro Filter instance.");
    
        SecurityManager securityManager = getSecurityManager();
        if (securityManager == null) {
            String msg = "SecurityManager property must be set.";
            throw new BeanInitializationException(msg);
        }
    
        if (!(securityManager instanceof WebSecurityManager)) {
            String msg = "The security manager does not implement the WebSecurityManager interface.";
            throw new BeanInitializationException(msg);
        }
    
        FilterChainManager manager = createFilterChainManager();
    
        //Expose the constructed FilterChainManager by first wrapping it in a
        // FilterChainResolver implementation. The AbstractShiroFilter implementations
        // do not know about FilterChainManagers - only resolvers:
        PathMatchingFilterChainResolver chainResolver = new PathMatchingFilterChainResolver();
        chainResolver.setFilterChainManager(manager);
    
        //Now create a concrete ShiroFilter instance and apply the acquired SecurityManager and built
        //FilterChainResolver.  It doesn't matter that the instance is an anonymous inner class
        //here - we're just using it because it is a concrete AbstractShiroFilter instance that accepts
        //injection of the SecurityManager and FilterChainResolver:
        return new SpringShiroFilter((WebSecurityManager) securityManager, chainResolver);
    }

    createFilterChainManager方法比较重要,包含以下必要操作:

    1. DefaultFilterChainManager对象的创建

    2. defaultFilters的获取和相关url的填充

    3. 自定义filters的获取和相关url的填充

    4. 获取FilterChainDefinitionMap (这个就是配置文件中的filterChainDefinitions的映射关系)

    5. 对url和权限的映射关系作处理

    默认的DefaultFilter枚举中包含以下filter类:

    anon(AnonymousFilter.class),
    authc(FormAuthenticationFilter.class),
    authcBasic(BasicHttpAuthenticationFilter.class),
    logout(LogoutFilter.class),
    noSessionCreation(NoSessionCreationFilter.class),
    perms(PermissionsAuthorizationFilter.class),
    port(PortFilter.class),
    rest(HttpMethodPermissionFilter.class),
    roles(RolesAuthorizationFilter.class),
    ssl(SslFilter.class),
    user(UserFilter.class);

    执行doFilter方法

    看下内部类 SpringShiroFilter:

    private static final class SpringShiroFilter extends AbstractShiroFilter {
    
        protected SpringShiroFilter(WebSecurityManager webSecurityManager, FilterChainResolver resolver) {
            super();
            if (webSecurityManager == null) {
                throw new IllegalArgumentException("WebSecurityManager property cannot be null.");
            }
            setSecurityManager(webSecurityManager);
            if (resolver != null) {
                setFilterChainResolver(resolver);
            }
        }
    }

    这里写图片描述

    在org.apache.shiro.web.servlet.OncePerRequestFilter中实现了doFilter方法:

    public final void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
        String alreadyFilteredAttributeName = getAlreadyFilteredAttributeName();
        if ( request.getAttribute(alreadyFilteredAttributeName) != null ) {
            log.trace("Filter '{}' already executed.  Proceeding without invoking this filter.", getName());
            filterChain.doFilter(request, response);
        } else //noinspection deprecation
            if (/* added in 1.2: */ !isEnabled(request, response) ||
                /* retain backwards compatibility: */ shouldNotFilter(request) ) {
            log.debug("Filter '{}' is not enabled for the current request.  Proceeding without invoking this filter.",
                    getName());
            filterChain.doFilter(request, response);
        } else {
            // Do invoke this filter...
            log.trace("Filter '{}' not yet executed.  Executing now.", getName());
            request.setAttribute(alreadyFilteredAttributeName, Boolean.TRUE);
    
            try {
                doFilterInternal(request, response, filterChain);
            } finally {
                // Once the request has finished, we're done and we don't
                // need to mark as 'already filtered' any more.
                request.removeAttribute(alreadyFilteredAttributeName);
            }
        }
    }

    三种情况,分为两条路线:
    1. filterChain.doFilter(request, response); 直接放行
    2. doFilterInternal(request, response, filterChain); 走子类实现

    在org.apache.shiro.web.servlet.AbstractShiroFilter实现doFilterInternal:

    protected void doFilterInternal(ServletRequest servletRequest, ServletResponse servletResponse, final FilterChain chain)
            throws ServletException, IOException {
    
        Throwable t = null;
    
        try {
            final ServletRequest request = prepareServletRequest(servletRequest, servletResponse, chain);
            final ServletResponse response = prepareServletResponse(request, servletResponse, chain);
    
            final Subject subject = createSubject(request, response);
    
            //noinspection unchecked
            subject.execute(new Callable() {
                public Object call() throws Exception {
                    updateSessionLastAccessTime(request, response);
                    executeChain(request, response, chain);
                    return null;
                }
            });
        } catch (ExecutionException ex) {
            t = ex.getCause();
        } catch (Throwable throwable) {
            t = throwable;
        }
    
        if (t != null) {
            if (t instanceof ServletException) {
                throw (ServletException) t;
            }
            if (t instanceof IOException) {
                throw (IOException) t;
            }
            //otherwise it's not one of the two exceptions expected by the filter method signature - wrap it in one:
            String msg = "Filtered request failed.";
            throw new ServletException(msg, t);
        }
    }

    将HttpServletRequest和HttpServletResponse包装成shiro自己的ShiroHttpServletRequest和ShiroHttpServletResponse。

    利用包装后的对象创建Subject。

    然后是执行subject的execute的方法。

    protected void executeChain(ServletRequest request, ServletResponse response, FilterChain origChain)
            throws IOException, ServletException {
        FilterChain chain = getExecutionChain(request, response, origChain);
        chain.doFilter(request, response);
    }

    获取的FilterChain是一个代理的ProxiedFilterChain,持有自己的Filter集合,重写doFilter方法:取自己持有的Filter集合,一个个执行其doFilter方法,当所有的Filter都执行完后,再执行servlet的FilterChain。

    后面的过程就是一个原始的FilterChain的执行过程。

    可以想象,原生的Filter链似乎也是这样一个执行过程,遍历web.xml中配置的所有Filter。

    整个过程就是代理模式的运用。

    这里写图片描述

  • 相关阅读:
    牛客挑战赛48E速度即转发【带修莫队,分块】
    P3180[HAOI2016]地图【圆方树,莫队,分块】
    Jetty 教程
    Leetcode 238. Product of Array Except Self
    WebService [Debug] undefined element declaration 's:schema'
    WebService [Debug] java.net.BindException: Can't assign requested address
    SQL Server 四种排序, ROW_NUMBER() /RANK() /DENSE_RANK() /ntile() over()
    Leetcode 110 判断二叉树是否为平衡二叉树
    WebService 使用JDK开发WebService
    WebService [Debug] javax.xml.ws.WebServiceException: Undefined port type
  • 原文地址:https://www.cnblogs.com/lucare/p/8679136.html
Copyright © 2011-2022 走看看