Shiro初始化过程

从Shiro配置中可以看出,Shiro的起始类是DelegatingFilterProxy,DelegatingFilterProxy委托给Shiro自己的一系列Filter做过滤处理,这是后话;

SpringMvc中web.xml配置:

    <!-- shiroFilter -->
    <filter>
        <filter-name>shiroFilter</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
        <init-param>
            <param-name>targetFilterLifecycle</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>shiroFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

SpringBoot中的配置代码:

    @Bean
    public FilterRegistrationBean authorizeFilter() {
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();

        DelegatingFilterProxy proxy = new DelegatingFilterProxy();
        proxy.setTargetFilterLifecycle(true);
        proxy.setTargetBeanName("shiroFilter");

        filterRegistrationBean.setName("authorizeFilter");
        filterRegistrationBean.setFilter(proxy);
        filterRegistrationBean.setUrlPatterns(Lists.newArrayList("/*"));
        filterRegistrationBean.setOrder(2);

        return filterRegistrationBean;
    }

关键在于这行代码,设置目标类的名称,也就是真正处理业务的Java对象:

proxy.setTargetBeanName("shiroFilter");

由此可见,DelegatingFilterProxy代理的是shiroFilter这个类,那么这个类在哪里呢?(下面是SpringBoot中的代码,以下的所有代码均为SpringBoot中的代码)

    @Bean
    public CustomShiroFilterFactoryBean shiroFilter(DefaultWebSecurityManager securityManager,
                                                    CustomFilter customFilter,
                                                    AnyRolesAuthorizationFilter anyRolesAuthorizationFilter,
                                                    AnyPermissionsAuthorizationFilter anyPermissionsAuthorizationFilter) {
        CustomShiroFilterFactoryBean shiroFilter = new CustomShiroFilterFactoryBean();
        shiroFilter.setSecurityManager(securityManager);

        shiroFilter.setLoginUrl("/admin/index/unAuthenticated");
        shiroFilter.setUnauthorizedUrl("/admin/index/unAuthorized");

        Map<String, Filter> filters = new HashMap<>();
        filters.put("c", customFilter);
        filters.put("roles", anyRolesAuthorizationFilter);
        filters.put("perms", anyPermissionsAuthorizationFilter);
        shiroFilter.setFilters(filters);

        String shiroChains = "";
        try {
            shiroChains = IOUtils.toString(ShiroConfig.class.getClassLoader().getResourceAsStream("shiro-chains.txt"), "UTF-8");
        } catch (IOException e) {
            e.printStackTrace();
        }
        shiroFilter.setFilterChainDefinitions(shiroChains);

        return shiroFilter;
    }

这段代码想必都不陌生,这里不做赘述,现在可以回到DelegatingFilterProxy中了。

DelegatingFilterProxy继承自GenericFilterBean,GenericFilterBean实现了Filter中的init(FilterConfig),并且提供了一个无参的initFilterBean()供子类实现:

DelegatingFilterProxy # initFilterBean 初始化过滤器实例:

        @Override
	protected void initFilterBean() throws ServletException {
		synchronized (this.delegateMonitor) {
			if (this.delegate == null) {
				// If no target bean name specified, use filter name.
				if (this.targetBeanName == null) {
					this.targetBeanName = getFilterName();
				}
				// Fetch Spring root application context and initialize the delegate early,
				// if possible. If the root application context will be started after this
				// filter proxy, we'll have to resort to lazy initialization.
				WebApplicationContext wac = findWebApplicationContext();
				if (wac != null) {
					this.delegate = initDelegate(wac);
				}
			}
		}
	}

DelegatingFilterProxy # initDelegate

        protected Filter initDelegate(WebApplicationContext wac) throws ServletException {
		Filter delegate = wac.getBean(getTargetBeanName(), Filter.class);
		if (isTargetFilterLifecycle()) {
			delegate.init(getFilterConfig());
		}
		return delegate;
	}
 
Filter delegate = wac.getBean(getTargetBeanName(), Filter.class);

从wac(WebApplicationContext)中取getTargetBeanName这个Bean,还记得这行代码吗?

proxy.setTargetBeanName("shiroFilter");

所以现在取的就是“shiroFilter”命名的Bean,也就是文章刚开始由@Bean注解的CustomShiroFilterFactoryBean这个类,这个类是我自定义的一个类,继承自ShiroFilterFactoryBean:

public class CustomShiroFilterFactoryBean extends ShiroFilterFactoryBean {

}

ShiroFactoryBean实现了FactoryBean,在Spring中有两种Bean的实现方式,一种就是普通的Java类,另一种就是实现了FactoryBean的Java类,实现了FactoryBean的Java类在取它的实例时,并不是取它自身,而是调用它的getObject来取具体的实例;

public interface FactoryBean<T> {
	T getObject() throws Exception;
}

ShiroFactoryBean是如何实现该方法的呢?咱们接着走:

ShiroFilterFactoryBean # getObject

    public Object getObject() throws Exception {
        if (this.instance == null) {
            this.instance = this.createInstance();
        }

        return this.instance;
    }

初始化的时候,this.instance = null;所以执行:

ShiroFilterFacotyBean # createInstance

    protected AbstractShiroFilter createInstance() throws Exception {
        log.debug("Creating Shiro Filter instance.");
        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 {
            FilterChainManager manager = this.createFilterChainManager();
            PathMatchingFilterChainResolver chainResolver = new PathMatchingFilterChainResolver();
            chainResolver.setFilterChainManager(manager);
            return new ShiroFilterFactoryBean.SpringShiroFilter((WebSecurityManager)securityManager, chainResolver);
        }
    }

其中主要有3个步骤:

1.取安全管理器 SecurityManager securityManager = this.getSecurityManager();(在配置时注入)

2.创建过滤器链管理器 FilterChainManager manager = this.createFilterChainManager();

3.创建返回Shiro过滤器 new ShiroFilterFactoryBean.SpringShiroFilter(...);

至此,初始化过程就完成了。

其中第2个步骤最为重要,是自定义加载方式最好的时机:

ShiroFilterFactoryBean # createFilterChainManager

    protected FilterChainManager createFilterChainManager() {
        DefaultFilterChainManager manager = new DefaultFilterChainManager();
        Map<String, Filter> defaultFilters = manager.getFilters();
        Iterator var3 = defaultFilters.values().iterator();

        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);
                }
            }
        }

        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();
                manager.createChain(url, chainDefinition);
            }
        }

        return manager;
    }

取默认的过滤器链配置,其中包含最基本的过滤器,比如 anon、roles、perms、authc等;

DefaultFilterChainManager manager = new DefaultFilterChainManager();

 

public enum DefaultFilter {
    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);
}

创建过滤器链,将自定义的拦截放入过滤器链中,其中filterChains非常重要,在动态配置拦截的时候将会用到:

manager.createChain(url, chainDefinition);
  1. DefaultFilterChainManager # createChain 创建chain,参数依次是要拦截的url以及权限控制;
  2. DefaultFilterChainManager # addToChain 一些参数校验;
  3. DefaultFilterChainManager # ensureChain 对filterChains做验证,保证有此chain;
  4. 最后将chain中添加此filter;

现在,初始化过程就结束了。

 

其中需要知道的是,DelegatingFilterProxy是属于web级别的过滤器,而SpringMvc中的HandlerInterceptor是在DispatcherServlet分发请求时做的拦截,也就是说被Shiro委托的一系列Filter都在请求到达DispatcherServlet前执行,只有知道了整个系统的初始化过程、执行过程,我们才能设计出更优秀的系统,即便出现问题时也能快速定位。

 

Shiro拦截请求以及做身份、权限验证的过程,将在下一篇文章中讲述。

谢谢。

 

公众号搜索:以镒称铢

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值