shiro源码分析之-shiro-web核心过滤器源码分析

一、SpringShiroFilter

1.继承关系

SpringShiroFilter就是shiro-web框架的核心过滤器,继承关系如下:

SpringShiroFilter

类实体(一个内部类):

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

        }
    }
}

二、核心过滤器实例化过程源码分析

1.配置类中配置ShiroFilterFactoryBean的@Bean对象

@Bean(name = "shiroFilter")
   public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
      ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();  
      shiroFilterFactoryBean.setSecurityManager(securityManager);  

      shiroFilterFactoryBean.setLoginUrl("/pub/need_login");          
      shiroFilterFactoryBean.setUnauthorizedUrl("/pub/no_permission");   

      Map<String, Filter> filterMap = new LinkedHashMap<>();
      filterMap.put("authc", new JWTFilter());
      shiroFilterFactoryBean.setFilters(filterMap);

      Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();

      // 这里配置路径是不带server.servlet.context-path: /admin的
      filterChainDefinitionMap.put("/auth/pub/**", "anon");
      filterChainDefinitionMap.put("/swagger-ui.html", "anon");
      filterChainDefinitionMap.put("/webjars/**", "anon");
      filterChainDefinitionMap.put("/v2/**", "anon");
      filterChainDefinitionMap.put("/swagger-resources/**", "anon");
      filterChainDefinitionMap.put("/**", "authc");              // 最后添加防止漏配
      shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
      return shiroFilterFactoryBean;
   }

这是实例化核心过滤器的入口,ShiroFilterFactoryBean是一个实现了FactoryBean接口的类,可以看出会通过getObject()方法获取核心过滤器的对象。

2.ShiroFilterFactoryBean源码分析

可以看到ShiroFilterFactoryBean实现了FactoryBean和BeanPostProcessor接口,是一个生产bean的类。

public class ShiroFilterFactoryBean implements FactoryBean, BeanPostProcessor {
    private static final transient Logger log = LoggerFactory.getLogger(ShiroFilterFactoryBean.class);
    // 重要的安全管理器,服务shiro的整个生命周期
    private SecurityManager securityManager;
    // 保存自定义的Filter
    private Map<String, Filter> filters = new LinkedHashMap();
    // 保存配置的路径和处理filter之间的关系,注意是有序的
    private Map<String, String> filterChainDefinitionMap = new LinkedHashMap();
    // 登录接口路径
    private String loginUrl;
    // 登录成功后跳转到的路径
    private String successUrl;
    // 无权限跳转的路径
    private String unauthorizedUrl;
    // shiro核心过滤器实例引用
    private AbstractShiroFilter instance;

    public ShiroFilterFactoryBean() {
    }
    
    // ......
    // 获取shiro核心过滤器对象,被springIOC调用
    public Object getObject() throws Exception {
        if (this.instance == null) {
            this.instance = this.createInstance();
        }

        return this.instance;
    }

    // FactoryBean返回的实例类型
    public Class getObjectType() {
        return ShiroFilterFactoryBean.SpringShiroFilter.class;
    }

    // FactoryBean返回的实例是否单例,单例
    public boolean isSingleton() {
        return true;
    }
    // ......
    // 
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if (bean instanceof Filter) {
            log.debug("Found filter chain candidate filter '{}'", beanName);
            Filter filter = (Filter)bean;
            this.applyGlobalPropertiesIfNecessary(filter);
            this.getFilters().put(beanName, filter);
        } else {
            log.trace("Ignoring non-Filter bean '{}'", beanName);
        }

        return bean;
    }

    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }
    // ......
}

既然是一个FactoryBean就从getObject()方法下手一步步的分析吧

public Object getObject() throws Exception {
    if (this.instance == null) {
        this.instance = this.createInstance();// 向下继续
    }

    return this.instance;
}


protected AbstractShiroFilter createInstance() throws Exception {
    log.debug("Creating Shiro Filter instance.");
    // 获取配置的核心SecurityManager
    SecurityManager securityManager = this.getSecurityManager();
    String msg;
    if (securityManager == null) {
        msg = "SecurityManager property must be set.";
        throw new BeanInitializationException(msg);
    } else if (!(securityManager instanceof WebSecurityManager)) {
        msg = "The security manager does not implement the WebSecurityManager interface.";
        throw new BeanInitializationException(msg);
    } else {
        // 【2.1】创建过滤器链管理器
        FilterChainManager manager = this.createFilterChainManager();
        // 【2.2】创建一个默认的路径匹配过滤器链解析器
        PathMatchingFilterChainResolver chainResolver = new PathMatchingFilterChainResolver();
        // 这里就是简单替换默认构造创建的FilterChainManager,使用【2.1】加工好的
        chainResolver.setFilterChainManager(manager);
        // 【2.3】使用过滤器链管理器、解析器创建shiro核心过滤器对象返回
        return new ShiroFilterFactoryBean.SpringShiroFilter((WebSecurityManager)securityManager, chainResolver);
    }
}
2.1.创建过滤器链管理器
protected FilterChainManager createFilterChainManager() {
    // 【2.1.1】创建默认的过滤器链管理器对象,这里添加了一些默认的过滤器
    DefaultFilterChainManager manager = new DefaultFilterChainManager();
    Map<String, Filter> defaultFilters = manager.getFilters();
    Iterator var3 = defaultFilters.values().iterator();

    // 【2.1.2】遍历默认的过滤器进行需要性的全局那三个路径的配置
    while(var3.hasNext()) {
        Filter filter = (Filter)var3.next();
        this.applyGlobalPropertiesIfNecessary(filter);
    }

    // 遍历自定义过滤器进行需要性的全局那三个路径的配置,配置过滤器别名,
    // 并覆盖性的添加到默认的过滤器链管理器中
    Map<String, Filter> filters = this.getFilters();
    String name;
    Filter filter;
    if (!CollectionUtils.isEmpty(filters)) {
        for(Iterator var10 = filters.entrySet().iterator(); var10.hasNext(); manager.addFilter(name, filter, false)) {
            Entry<String, Filter> entry = (Entry)var10.next();
            name = (String)entry.getKey();
            filter = (Filter)entry.getValue();
            this.applyGlobalPropertiesIfNecessary(filter);
            if (filter instanceof Nameable) {
                ((Nameable)filter).setName(name);
            }
        }
    }

    // 【2.1.3】根据配置的路径和处理filter之间的关系map进行路径与filter之间的关联处理
    Map<String, String> chains = this.getFilterChainDefinitionMap();
    if (!CollectionUtils.isEmpty(chains)) {
        Iterator var12 = chains.entrySet().iterator();

        while(var12.hasNext()) {
            Entry<String, String> entry = (Entry)var12.next();
            String url = (String)entry.getKey();
            String chainDefinition = (String)entry.getValue();
            // 配置filter负责处理的路径,重点,重点,重点......
            manager.createChain(url, chainDefinition);
        }
    }

    return manager;
}
2.1.1.添加默认的过滤器(12个)
public DefaultFilterChainManager() {
    this.addDefaultFilters(false);
}
protected void addDefaultFilters(boolean init) {
    // DefaultFilter是一个枚举类,里面就保存了那12个过滤器,进去看一下
    DefaultFilter[] var2 = DefaultFilter.values();
    int var3 = var2.length;

    // 循环遍历将12个过滤器添加到默认的过滤器链管理器中
    for(int var4 = 0; var4 < var3; ++var4) {
        DefaultFilter defaultFilter = var2[var4];
        this.addFilter(defaultFilter.name(), defaultFilter.newInstance(), init, false);
    }

}
public enum DefaultFilter {
    anon(AnonymousFilter.class),
    authc(FormAuthenticationFilter.class),
    authcBasic(BasicHttpAuthenticationFilter.class),
    authcBearer(BearerHttpAuthenticationFilter.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);
2.1.2 默认过滤器全局需要性配置三路径
private void applyGlobalPropertiesIfNecessary(Filter filter) {
    // 如果需要配置登录路径
    this.applyLoginUrlIfNecessary(filter);
    // 如果需要配置登录成功跳转路径
    this.applySuccessUrlIfNecessary(filter);
    // 如果需要配置无访问权限跳转的路径
    this.applyUnauthorizedUrlIfNecessary(filter);
}
// 如果需要配置登录路径
private void applyLoginUrlIfNecessary(Filter filter) {
    String loginUrl = this.getLoginUrl();
    // 如果是AccessControlFilter过滤器
    if (StringUtils.hasText(loginUrl) && filter instanceof AccessControlFilter) {
        AccessControlFilter acFilter = (AccessControlFilter)filter;
        String existingLoginUrl = acFilter.getLoginUrl();
        // 如果过滤器没有自定义配置这个路径就配置全局路径
        if ("/login.jsp".equals(existingLoginUrl)) {
            acFilter.setLoginUrl(loginUrl);
        }
    }

}
// 如果需要配置登录成功跳转路径
private void applySuccessUrlIfNecessary(Filter filter) {
    String successUrl = this.getSuccessUrl();
    // 如果是AuthenticationFilter过滤器
    if (StringUtils.hasText(successUrl) && filter instanceof AuthenticationFilter) {
        AuthenticationFilter authcFilter = (AuthenticationFilter)filter;
        String existingSuccessUrl = authcFilter.getSuccessUrl();
        // 如果过滤器没有自定义配置这个路径就配置全局路径
        if ("/".equals(existingSuccessUrl)) {
            authcFilter.setSuccessUrl(successUrl);
        }
    }

}
// 如果需要配置无访问权限跳转的路径
private void applyUnauthorizedUrlIfNecessary(Filter filter) {
    String unauthorizedUrl = this.getUnauthorizedUrl();
    // 如果是AuthenticationFilter过滤器
    if (StringUtils.hasText(unauthorizedUrl) && filter instanceof AuthorizationFilter) {
        AuthorizationFilter authzFilter = (AuthorizationFilter)filter;
        String existingUnauthorizedUrl = authzFilter.getUnauthorizedUrl();
        // 如果过滤器没有自定义配置这个路径就配置全局路径
        if (existingUnauthorizedUrl == null) {
            authzFilter.setUnauthorizedUrl(unauthorizedUrl);
        }
    }

}
2.1.3 路径和处理filter之间关系处理

先说结论,路径和 filter配置中,一个路径可以配置多个filter,配置方式如下:

filterChainDefinitionMap.put("/auth/pub/**", "authc,perms[amdin,guest],roles[amdin]");

—————————————————————分割线——————————————————

// chainName就是配置的url
// chainDefinition就是filter名和规则,map的值
public void createChain(String chainName, String chainDefinition) {
    if (!StringUtils.hasText(chainName)) {
        throw new NullPointerException("chainName cannot be null or empty.");
    } else if (!StringUtils.hasText(chainDefinition)) {
        throw new NullPointerException("chainDefinition cannot be null or empty.");
    } else {
        if (log.isDebugEnabled()) {
            log.debug("Creating chain [" + chainName + "] from String definition [" + chainDefinition + "]");
        }
		
        // 处理map的值,比如chainDefinition=“perms[admin,role],kk[dd,ee],auth”
        // 处理完后为["perms[admin,role]","kk[dd,ee]",auth]
        String[] filterTokens = this.splitChainDefinition(chainDefinition);
        String[] var4 = filterTokens;
        int var5 = filterTokens.length;

        // 循环遍历处理过的map值的数组
        for(int var6 = 0; var6 < var5; ++var6) {
            String token = var4[var6];
            // 比如token=“perms[dd,ee,ff]”,处理完后为["perms","dd,ee,ff"]
            String[] nameConfigPair = this.toNameConfigPair(token);
            // 建立关系
            this.addToChain(chainName, nameConfigPair[0], nameConfigPair[1]);
        }

    }
}
// chainName就是url
// filterName就是过滤器名
// chainSpecificFilterConfig就是规则
public void addToChain(String chainName, String filterName, String chainSpecificFilterConfig) {
    if (!StringUtils.hasText(chainName)) {
        throw new IllegalArgumentException("chainName cannot be null or empty.");
    } else {
        Filter filter = this.getFilter(filterName);
        if (filter == null) {
            throw new IllegalArgumentException("There is no filter with name '" + filterName + "' to apply to chain [" + chainName + "] in the pool of available Filters.  Ensure a filter with that name/path has first been registered with the addFilter method(s).");
        } else {
            // 重点,重点,重点----这里就配置此filter负责处理的路径和处理规则
            this.applyChainConfig(chainName, filter, chainSpecificFilterConfig);
            // 这里可以看出一个路径可以配置多个filter
            NamedFilterList chain = this.ensureChain(chainName);
            chain.add(filter);
        }
    }
}
2.2. 创建一个默认的路径匹配过滤器链解析器
public PathMatchingFilterChainResolver() {
    this.filterChainManager = new DefaultFilterChainManager();
}

跟【2.1.1.添加默认的过滤器(12个)】逻辑一样了

public DefaultFilterChainManager() {
    this.addDefaultFilters(false);
}
2.3. 使用过滤器链管理器、解析器创建shiro核心过滤器对象返回

有了SecurityManager和FilterChainResolver,shiro的核心过滤器就可以在web中逍遥称霸了

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

        }
    }
}

三、shiro核心过滤器调用过程分析

SpringShiroFilter是shiro的核心过滤器,继承了AbstractShiroFilter并简单的设置了两个属性的值**(WebSecurityManager,FilterChainResolver),所以直接看AbstractShiroFilterdoFilterInternal**方法

/*AbstractShiroFilter*/

protected void doFilterInternal(ServletRequest servletRequest, ServletResponse servletResponse, final FilterChain chain) throws ServletException, IOException {
    Throwable t = null;

    try {
        // 将HttpServletRequest包装成shiro的HttpServletRequest
        final ServletRequest request = this.prepareServletRequest(servletRequest, servletResponse, chain);
        // 将HttpServletResponse包装成shiro的HttpServletResponse
        final ServletResponse response = this.prepareServletResponse(request, servletResponse, chain);
        // 【1】重点,重点,重点------创建用户主体Subject
        Subject subject = this.createSubject(request, response);
        // 异步执行shiro维护的过滤器链
        subject.execute(new Callable() {
            public Object call() throws Exception {
                // 【2】更新session最后访问时间
                AbstractShiroFilter.this.updateSessionLastAccessTime(request, response);
                // 【3】执行shiro过滤器链
                AbstractShiroFilter.this.executeChain(request, response, chain);
                return null;
            }
        });
    } catch (ExecutionException var8) {
        t = var8.getCause();
    } catch (Throwable var9) {
        t = var9;
    }

    // 执行shiro维护的过滤器链之前异常检验
    if (t != null) {
        if (t instanceof ServletException) {
            throw (ServletException)t;
        } else if (t instanceof IOException) {
            throw (IOException)t;
        } else {
            String msg = "Filtered request failed.";
            throw new ServletException(msg, t);
        }
    }
}

1.创建用户主体Subject

这是一个重点

protected WebSubject createSubject(ServletRequest request, ServletResponse response) {
    // 根据传入的SecurityManager和request、response创建一个WebSubject
    return (new Builder(this.getSecurityManager(), request, response)).buildWebSubject();
}
/**WebSubject**/

public Builder(SecurityManager securityManager, ServletRequest request, ServletResponse response) {
    // 【1.1】调用父构造器,创建SubjectContext
    super(securityManager);
    if (request == null) {
        throw new IllegalArgumentException("ServletRequest argument cannot be null.");
    } else if (response == null) {
        throw new IllegalArgumentException("ServletResponse argument cannot be null.");
    } else {
        this.setRequest(request);
        this.setResponse(response);
    }
}
1.1.在Builder中创建SubjectContext
/** org.apache.shiro.subject.Builder **/

public Builder(SecurityManager securityManager) {
    if (securityManager == null) {
        throw new NullPointerException("SecurityManager method argument cannot be null.");
    } else {
        this.securityManager = securityManager;
        // 创建SubjectContext,这里需要重点注意一下,是调用WebSubject中的方法,不是Subject中的方法
        this.subjectContext = this.newSubjectContextInstance();
        if (this.subjectContext == null) {
            throw new IllegalStateException("Subject instance returned from 'newSubjectContextInstance' cannot be null.");
        } else {
            this.subjectContext.setSecurityManager(securityManager);
        }
    }
}

这里需要重点注意一下,是调用WebSubject中的方法,不是Subject中的方法

/*org.apache.shiro.web.subject.WebSubject*/

protected SubjectContext newSubjectContextInstance() {
    return new DefaultWebSubjectContext();
}

看一看DefaultWebSubjectContext是个啥,就是定义了一堆静态属性,它的父类还定义了一堆静态属性

public class DefaultWebSubjectContext extends DefaultSubjectContext implements WebSubjectContext {
    private static final long serialVersionUID = 8188555355305827739L;
    private static final String SERVLET_REQUEST = DefaultWebSubjectContext.class.getName() + ".SERVLET_REQUEST";
    private static final String SERVLET_RESPONSE = DefaultWebSubjectContext.class.getName() + ".SERVLET_RESPONSE";

    public DefaultWebSubjectContext() {
    }
    
    // ......
    
}


public class DefaultSubjectContext extends MapContext implements SubjectContext {
    private static final String SECURITY_MANAGER = DefaultSubjectContext.class.getName() + ".SECURITY_MANAGER";
    private static final String SESSION_ID = DefaultSubjectContext.class.getName() + ".SESSION_ID";
    private static final String AUTHENTICATION_TOKEN = DefaultSubjectContext.class.getName() + ".AUTHENTICATION_TOKEN";
    private static final String AUTHENTICATION_INFO = DefaultSubjectContext.class.getName() + ".AUTHENTICATION_INFO";
    private static final String SUBJECT = DefaultSubjectContext.class.getName() + ".SUBJECT";
    private static final String PRINCIPALS = DefaultSubjectContext.class.getName() + ".PRINCIPALS";
    private static final String SESSION = DefaultSubjectContext.class.getName() + ".SESSION";
    private static final String AUTHENTICATED = DefaultSubjectContext.class.getName() + ".AUTHENTICATED";
    private static final String HOST = DefaultSubjectContext.class.getName() + ".HOST";
    public static final String SESSION_CREATION_ENABLED = DefaultSubjectContext.class.getName() + ".SESSION_CREATION_ENABLED";
    public static final String PRINCIPALS_SESSION_KEY = DefaultSubjectContext.class.getName() + "_PRINCIPALS_SESSION_KEY";
    public static final String AUTHENTICATED_SESSION_KEY = DefaultSubjectContext.class.getName() + "_AUTHENTICATED_SESSION_KEY";
    private static final transient Logger log = LoggerFactory.getLogger(DefaultSubjectContext.class);

    public DefaultSubjectContext() {
    }
    
    // ......
    
}
1.2.通过Builder创建WebSubject
public WebSubject buildWebSubject() {
    // 调用父类的构建方法,看下面
    Subject subject = super.buildSubject();
    if (!(subject instanceof WebSubject)) {
        String msg = "Subject implementation returned from the SecurityManager was not a " + WebSubject.class.getName() + " implementation.  Please ensure a Web-enabled SecurityManager has been configured and made available to this builder.";
        throw new IllegalStateException(msg);
    } else {
        return (WebSubject)subject;
    }
}
public Subject buildSubject() {
    // 可以看出使用我们传入的SecurityManager实例创建的Subject
    return this.securityManager.createSubject(this.subjectContext);
}

这样就要看DefaultWebSecurityManager的createSubject方法啦,但是它没有这个方法,那就去看它的父类DefaultSecurityManager

public Subject createSubject(SubjectContext subjectContext) {
    // 这里注意是调用DefaultWebSecurityManager中的copy方法返回的是一个DefaultWebSubjectContext
    SubjectContext context = this.copy(subjectContext);
    context = this.ensureSecurityManager(context);
    context = this.resolveSession(context);
    context = this.resolvePrincipals(context);
    // 使用SubjectFactory创建Subject,DefaultSubjectFactory是默认的实现类,可以配合别的实现类
    Subject subject = this.doCreateSubject(context);
    // 将Subject保存到SubjectDAO中,DefaultSubjectDAO是默认的实现类,可以配合别的实现类
    this.save(subject);
    return subject;
}
1.2.1. 使用工厂创建Subject
protected Subject doCreateSubject(SubjectContext context) {
    return this.getSubjectFactory().createSubject(context);
}

这里需要注意,上面获取的SubjectFactory的真实对象其实是在new DefaultWebSecurityManager时创建的默认***DefaultWebSubjectFactory***,返回的Subject是一个WebDelegatingSubject

/* org.apache.shiro.mgt.DefaultWebSubjectFactory */

 public Subject createSubject(SubjectContext context) {
        boolean isNotBasedOnWebSubject = context.getSubject() != null && !(context.getSubject() instanceof WebSubject);
     	// 校验是否为web环境
        if (context instanceof WebSubjectContext && !isNotBasedOnWebSubject) {
            WebSubjectContext wsc = (WebSubjectContext)context;
            SecurityManager securityManager = wsc.resolveSecurityManager();
            // 解析session
            Session session = wsc.resolveSession();
            boolean sessionEnabled = wsc.isSessionCreationEnabled();
            PrincipalCollection principals = wsc.resolvePrincipals();
            boolean authenticated = wsc.resolveAuthenticated();
            String host = wsc.resolveHost();
            ServletRequest request = wsc.resolveServletRequest();
            ServletResponse response = wsc.resolveServletResponse();
            return new WebDelegatingSubject(principals, authenticated, host, session, sessionEnabled, request, response, securityManager);
        } else {
            return super.createSubject(context);
        }
    }

2.更新session最后访问时间

session的生成去看本文件所在目录下的相关文章

protected void updateSessionLastAccessTime(ServletRequest request, ServletResponse response) {
    // 判断是不是web容器的HttpSession,因为shiro框架定义了自己的session,为了解耦web容器
    if (!this.isHttpSessions()) {
        Subject subject = SecurityUtils.getSubject();
        if (subject != null) {
            // 从用户主体中获取session()
            Session session = subject.getSession(false);
            if (session != null) {
                try {
                    // 如果session不为null,就在这里更新时间
                    session.touch();
                } catch (Throwable var6) {
                    log.error("session.touch() method invocation has failed.  Unable to update the corresponding session's last access time based on the incoming request.", var6);
                }
            }
        }
    }

}

3.执行shiro过滤器链

/*AbstractShiroFilter*/

protected void executeChain(ServletRequest request, ServletResponse response, FilterChain origChain) throws IOException, ServletException {
    	// 【3.1】根据请求的路径获取过滤器链
        FilterChain chain = this.getExecutionChain(request, response, origChain);
    	// 【3.2】执行已经处理好的shiro维护的过滤器链
        chain.doFilter(request, response);
    }
3.1根据请求的路径获取过滤器链
/*AbstractShiroFilter*/

protected FilterChain getExecutionChain(ServletRequest request, ServletResponse response, FilterChain origChain) {
    FilterChain chain = origChain;
    // 这里获取到的FilterChainResolver为PathMatchingFilterChainResolver实例
    FilterChainResolver resolver = this.getFilterChainResolver();
    if (resolver == null) {
        log.debug("No FilterChainResolver configured.  Returning original FilterChain.");
        return origChain;
    } else {
        // 【3.1.1】走这路,FilterChainResolver根据请求路径获取过滤器链
        FilterChain resolved = resolver.getChain(request, response, origChain);
        if (resolved != null) {
            log.trace("Resolved a configured FilterChain for the current request.");
            chain = resolved;
        } else {
            log.trace("No FilterChain configured for the current request.  Using the default.");
        }

        return chain;
    }
}
3.1.1.FilterChainResolver根据请求路径获取过滤器链
/*PathMatchingFilterChainResolver*/

public FilterChain getChain(ServletRequest request, ServletResponse response, FilterChain originalChain) {
    // 获取解析器维护的FilterChainManager,这里是【2.1】步创建的DefaultFilterChainManager实例
    FilterChainManager filterChainManager = this.getFilterChainManager();
    if (!filterChainManager.hasChains()) {
        return null;
    } else {
        // 获取请求url(已经去除了contextPath部分),代码很简单,这里不深入
        String requestURI = this.getPathWithinApplication(request);
        if (requestURI != null && !"/".equals(requestURI) && requestURI.endsWith("/")) {
            requestURI = requestURI.substring(0, requestURI.length() - 1);
        }
		// 获取所有的ChainName(就是配置的那些ANT路径)
        Iterator var6 = filterChainManager.getChainNames().iterator();

        String pathPattern;
        // 循环遍历直到找到第一个匹配的结果
        do {
            if (!var6.hasNext()) {
                return null;
            }

            pathPattern = (String)var6.next();
            if (pathPattern != null && !"/".equals(pathPattern) && pathPattern.endsWith("/")) {
                pathPattern = pathPattern.substring(0, pathPattern.length() - 1);
            }
            // 使用AntPathMatcher进行请求url与配置的url进行匹配
        } while(!this.pathMatches(pathPattern, requestURI));

        if (log.isTraceEnabled()) {
            log.trace("Matched path pattern [" + pathPattern + "] for requestURI [" + Encode.forHtml(requestURI) + "].  Utilizing corresponding filter chain...");
        }
		// 重点,重点,重点,看下面------从FilterChainManager中获取过滤器链
        return filterChainManager.proxy(originalChain, pathPattern);
    }
}
/*DefaultFilterChainManager*/

public FilterChain proxy(FilterChain original, String chainName) {
    // 获取url对应的过滤器集合,这个集合是在核心过滤器初始化时处理好的
    NamedFilterList configured = this.getChain(chainName);
    if (configured == null) {
        String msg = "There is no configured chain under the name/key [" + chainName + "].";
        throw new IllegalArgumentException(msg);
    } else {
        // 获取最终的过滤器链,看下面
        return configured.proxy(original);
    }
}

/*SimpleNamedFilterList*/
public FilterChain proxy(FilterChain orig) {
    	// 返回的过滤器链,里面还维护了一个原始链(就是顶级web容器过滤器链),这样shiro内部过滤器处理完后
    	// 还能够交由web过滤器链处理
        return new ProxiedFilterChain(orig, this);
    }
3.2.执行已经处理好的shiro维护的过滤器链

ProxiedFilterChain是我们最终返回的处理指定url的过滤器链

/*ProxiedFilterChain*/

public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
    // 如果过滤器不为null且没有全部执行完
    if (this.filters != null && this.filters.size() != this.index) {
        if (log.isTraceEnabled()) {
            log.trace("Invoking wrapped filter at index [" + this.index + "]");
        }
		// 类似递归的过滤链调用
        ((Filter)this.filters.get(this.index++)).doFilter(request, response, this);
    } else {
        if (log.isTraceEnabled()) {
            log.trace("Invoking original filter chain.");
        }

        // shiro过滤器链都调用完没有return或者shiro过滤器链为null则会继续调用web容器顶级的过滤器链
        this.orig.doFilter(request, response);
    }

}

到此shiro核心过滤器的调用过程就结束了。
如果错误之处欢迎指正!!!

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值