美文网首页
shiro原理分析

shiro原理分析

作者: 半透明_ac54 | 来源:发表于2017-05-18 19:49 被阅读0次
    • 1、shiro如何介入你的spring程序
      基本流程是

    调用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的原因。

    相关文章

      网友评论

          本文标题:shiro原理分析

          本文链接:https://www.haomeiwen.com/subject/xmwdxxtx.html