shiro原理分析

  • 1、shiro如何介入你的spring程序
    基本流程是

調(diào)用FilterRegistrationBean向spring注冊過濾器-->使用DelegatingFilterProxy代理過濾器-->代理過濾器以bean的形式獲取過濾器

shiro通過監(jiān)聽器來介入你的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授權(quán)過濾器代理類,該類繼承了GenericFilterBean通用過濾器類,并且可以像管理spring bean一樣,把過濾器作為一個bean來委托給spring管理其生存周期,其依賴關(guān)系如圖所示

依賴關(guān)系

該類實現(xiàn)了Filter接口,在過濾器初始化時,調(diào)用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();  //調(diào)用子類的初始化方法

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

在該方法的最后會調(diào)用initFilterBean()方法,該方法是別其子類DelegatingFilterProxy重寫了,所以會調(diào)用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);
    }

雖然該類沒有實現(xiàn)Filter接口,但是在getObject()返回的類中是實現(xiàn)了該接口的類,這是我當(dāng)時一直迷惑的地方,當(dāng)時一直在疑問,為什么ShiroFilterFactoryBean 類沒有實現(xiàn)Filter接口也可以被當(dāng)做過濾器注入,當(dāng)時我沒有注意到該類不是普通的spring Bean而是FactoryBean,spring獲取的Bean不是該類本身而是該類的getObject()方法返回的對象實例,在該創(chuàng)建實例方法中,最后返回的是SpringShiroFilter類,該類是**ShiroFilterFactoryBean **的一個靜態(tài)內(nèi)部類,傳入了securityManager,這也是我們能夠配置Shiro的核心組件SecurityManager的原因。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容