shiro原理分析

2017-05-18  本文已影响0人  半透明_ac54

调用FilterRegistrationBean向spring注册过滤器-->使用DelegatingFilterProxy代理过滤器-->代理过滤器以bean的形式获取过滤器

shiro通过监听器来介入你的spring程序,在配置的时候

    @Bean
    public FilterRegistrationBean filterRegistrationBean() {
        FilterRegistrationBean filterRegistration = new FilterRegistrationBean();
        filterRegistration.setFilter(new DelegatingFilterProxy("shiroFilter"));
        filterRegistration.setEnabled(true);
        filterRegistration.addUrlPatterns("/*");
        filterRegistration.setDispatcherTypes(DispatcherType.REQUEST);
        return filterRegistration;
    }

在set过滤器的时候使用了DelegatingFilterProxy授权过滤器代理类,该类继承了GenericFilterBean通用过滤器类,并且可以像管理spring bean一样,把过滤器作为一个bean来委托给spring管理其生存周期,其依赖关系如图所示

依赖关系
该类实现了Filter接口,在过滤器初始化时,调用GenericFilterBean的init()方法,其源代码如下所示
@Override
    public final void init(FilterConfig filterConfig) throws ServletException {
        Assert.notNull(filterConfig, "FilterConfig must not be null");
        if (logger.isDebugEnabled()) {
            logger.debug("Initializing filter '" + filterConfig.getFilterName() + "'");
        }

        this.filterConfig = filterConfig;

        // Set bean properties from init parameters.
        try {
            PropertyValues pvs = new FilterConfigPropertyValues(filterConfig, this.requiredProperties);
            BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
            ResourceLoader resourceLoader = new ServletContextResourceLoader(filterConfig.getServletContext());
            bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, this.environment));
            initBeanWrapper(bw);
            bw.setPropertyValues(pvs, true);
        }
        catch (BeansException ex) {
            String msg = "Failed to set bean properties on filter '" +
                filterConfig.getFilterName() + "': " + ex.getMessage();
            logger.error(msg, ex);
            throw new NestedServletException(msg, ex);
        }

        // Let subclasses do whatever initialization they like.
        initFilterBean();  //调用子类的初始化方法

        if (logger.isDebugEnabled()) {
            logger.debug("Filter '" + filterConfig.getFilterName() + "' configured successfully");
        }
    }

在该方法的最后会调用initFilterBean()方法,该方法是别其子类DelegatingFilterProxy重写了,所以会调用DelegatingFilterProxyinitFilterBean()方法,其运行栈如下所示

initFilterBean()-->initDelegate()

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);中从程序的上下文中获取bean,在这个地方获取的bean是一个FactoryBean,获取的不是他本身,而是其getObject()方法返回的对象,在上文中

  filterRegistration.setFilter(new DelegatingFilterProxy("shiroFilter"));
@Bean(name = "shiroFilter")
    public ShiroFilterFactoryBean shiroFilter(){
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
        bean.setSecurityManager(securityManager());
        bean.setLoginUrl("/api/user/login");
        bean.setUnauthorizedUrl("/api/user/unauthor");

        Map<String, Filter>filters = Maps.newHashMap();
        filters.put("perms", urlPermissionsFilter());
        filters.put("anon", new AnonymousFilter());
        bean.setFilters(filters);

        Map<String, String> chains = Maps.newHashMap();
        chains.put("/api/user/login", "anon");
        chains.put("/api/user/unauthor", "anon");
        chains.put("/api/user/forgetpw", "anon");
        chains.put("/api/user/register", "anon");
        chains.put("/api/user/requestSMSCode", "anon");
        chains.put("/base/**", "anon");
        chains.put("/css/**", "anon");
        chains.put("/layer/**", "anon");
        chains.put("/**", "authc");
        bean.setFilterChainDefinitionMap(chains);
        return bean;
    }

后面说了DelegatingFilterProxy类把名字为shiroFilter的Bean作为过滤器,注入的是**ShiroFilterFactoryBean **类,该类的getObject()方法为

public Object getObject() throws Exception {
        if (instance == null) {
            instance = createInstance();
        }
        return instance;
    }
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);
    }

虽然该类没有实现Filter接口,但是在getObject()返回的类中是实现了该接口的类,这是我当时一直迷惑的地方,当时一直在疑问,为什么ShiroFilterFactoryBean 类没有实现Filter接口也可以被当做过滤器注入,当时我没有注意到该类不是普通的spring Bean而是FactoryBean,spring获取的Bean不是该类本身而是该类的getObject()方法返回的对象实例,在该创建实例方法中,最后返回的是SpringShiroFilter类,该类是**ShiroFilterFactoryBean **的一个静态内部类,传入了securityManager,这也是我们能够配置Shiro的核心组件SecurityManager的原因。

上一篇下一篇

猜你喜欢

热点阅读