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方法比较重要,包含以下必要操作:
- 
DefaultFilterChainManager对象的创建
 - 
defaultFilters的获取和相关url的填充
 - 
自定义filters的获取和相关url的填充
 - 
获取FilterChainDefinitionMap (这个就是配置文件中的filterChainDefinitions的映射关系)
 - 对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。
整个过程就是代理模式的运用。

                
            
        
浙公网安备 33010602011771号