ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

SpringBoot整合shiro系列-SpingBoot是如何将shiroFilter注册到servlet容器中的

2021-05-25 18:04:55  阅读:299  来源: 互联网

标签:return SpringBoot SpingBoot filter servletContext new shiroFilter public String


一、先从配置类入手,主要是@Bean了一个ShiroFilterFactoryBean:

@Data
@Configuration
@Slf4j
@EnableConfigurationProperties(ShiroProperties.class)
public class ShiroConfiguration {

    //.......这里省略了大部分跟主题无关的配置代码

    

   
    /**
     * 这里名字叫 shiroFilter,后续通过FilterRegistrationBean从spring容器中向servlet容器中注册filter
     * @param securityManager
     * @return
     * @author 
     * @create 
     */
    @Bean(name = "shiroFilter")
    public ShiroFilterFactoryBean getShiroFilterFactoryBean (DefaultWebSecurityManager securityManager,
                                                             ShiroProperties sp,IUserService userService){
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        // 必须设置 SecurityManager
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        //配置shiroFilter子过滤器
        loadFilter(shiroFilterFactoryBean,getCasFilter(sp,userService),getJwtFilter(),getWeComFilter());
        //配置拦截规则
        loadShiroFilterChain(shiroFilterFactoryBean, sp);
        return shiroFilterFactoryBean;
    }

   /**
     * CAS过滤器
     */
    @Bean
    public CustomizedCasFilter getCasFilter(ShiroProperties sp, IUserService userService) {
        CustomizedCasFilter casFilter = new CustomizedCasFilter();
        //.......
        return casFilter;
    }

    /**
     * JWT过滤器
     *
     * @return
     * @author 
     * @create 2020年8月19日
     */
    @Bean
    public CustomizedJwtFilter getJwtFilter() {
        CustomizedJwtFilter jwtFilter = new CustomizedJwtFilter();
        return jwtFilter;
    }

    /**
     *  企业微信过滤器
     * @param
     * @return
     */
    @Bean
    public CustomizedWeComFilter getWeComFilter() {
        CustomizedWeComFilter weComFilter = new CustomizedWeComFilter();
        return weComFilter;
    }

    /**
     * 添加过滤器
     * @param bean
     * @param casFilter
     * @param jwtFilter
     */
    private void loadFilter(ShiroFilterFactoryBean bean,CasFilter casFilter,
                            CustomizedJwtFilter jwtFilter,
                            CustomizedWeComFilter weComFilter) {
        Map<String, Filter> filters = new HashMap<>();
        filters.put("cas", casFilter);
        filters.put("jwt", jwtFilter);
        filters.put("weCom",weComFilter);
        bean.setFilters(filters);
    }

    /**
     * 加载shiroFilter权限控制规则
     *
     * @author
     * @create
     */
    private void loadShiroFilterChain (ShiroFilterFactoryBean shiroFilterFactoryBean, ShiroProperties sp){
        //下面这些规则配置最好配置到配置文件中
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
        // shiro集成cas后,首先添加该规则
        filterChainDefinitionMap.put("/api/**", "jwt");
        filterChainDefinitionMap.put("/cas/**", "cas");
        filterChainDefinitionMap.put("/wecom/**", "weCom");
        filterChainDefinitionMap.put("/test/**", "anon");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
    }


    /**
     * 在spring容器处在某一声明周期时时,为shiro中的相关bean执行对应的bean生命周期方法
     *
     * @author
     * @create
     */
    @Bean(name = "lifecycleBeanPostProcessor")
    public LifecycleBeanPostProcessor getLifecycleBeanPostProcessor () {
        return new LifecycleBeanPostProcessor();
    }

    .......
}

 

 

二、ShiroFilterFactoryBean(源码解析,代码中注释带序号的为代码执行顺序)-- 向Spring容器中注入了SpringShiroFilter:

public class ShiroFilterFactoryBean implements FactoryBean, BeanPostProcessor {
    private static final transient Logger log = LoggerFactory.getLogger(ShiroFilterFactoryBean.class);
    private SecurityManager securityManager;
    //这里是我们向注入的多个filter 见配置类中的loadFilter()方法
    private Map<String, Filter> filters = new LinkedHashMap();
    private List<String> globalFilters = new ArrayList();
    //见配置类中loadShiroFilterChain 
    private Map<String, String> filterChainDefinitionMap;
    private String loginUrl;
    private String successUrl;
    private String unauthorizedUrl;
    private AbstractShiroFilter instance;

    public ShiroFilterFactoryBean() {
        this.globalFilters.add(DefaultFilter.invalidRequest.name());
        this.filterChainDefinitionMap = new LinkedHashMap();
    }

    public SecurityManager getSecurityManager() {
        return this.securityManager;
    }

    ......

    public Map<String, Filter> getFilters() {
        return this.filters;
    }

    public Map<String, String> getFilterChainDefinitionMap() {
        return this.filterChainDefinitionMap;
    }

    ......

    // 1、  这里会在spring容器加载的时候调用,向spring容器中注入getObject()返回的对象
    public Object getObject() throws Exception {
        if (this.instance == null) {
            //2、调用createInstance()方法
            this.instance = this.createInstance();
        }

        return this.instance;
    }

    public Class getObjectType() {
        return ShiroFilterFactoryBean.SpringShiroFilter.class;
    }

    public boolean isSingleton() {
        return true;
    }

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

     //4、在这个地方获取了shiroFilter中的子过滤器,即我们在配置类中设置的loadFilter()
        Map<String, Filter> filters = this.getFilters();
        String name;
        Filter filter;
        if (!CollectionUtils.isEmpty(filters)) {

        //5、这个地方迭代,并将子过滤器添加到了manager中
            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);
                }
            }
        }

        manager.setGlobalFilters(this.globalFilters);
        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();
          //这里很重要 后面DefaultFilterChainManager filterChains属性在这里添加值
                manager.createChain(url, chainDefinition);
            }
        }

     //这里很重要 后面DefaultFilterChainManager filterChains属性在这里添加值
        manager.createDefaultChain("/**");
        return manager;
    }

    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 {

           //3、调用createFilterChainManager()
            FilterChainManager manager = this.createFilterChainManager();
            PathMatchingFilterChainResolver chainResolver = new PathMatchingFilterChainResolver();

            //6、将manager注入到chainResolver中,此时的manager有子过滤器,因而chainResolver也是可以获取到子过滤器的
            chainResolver.setFilterChainManager(manager);

       //7、返回SpringShiroFilter对象,即向Spring容器中注入SpringShiroFilter bean对象(带chain)
            return new ShiroFilterFactoryBean.SpringShiroFilter((WebSecurityManager)securityManager, chainResolver);
        }
    }

   //.........删除无关代码

    private void applyGlobalPropertiesIfNecessary(Filter filter) {
        this.applyLoginUrlIfNecessary(filter);
        this.applySuccessUrlIfNecessary(filter);
        this.applyUnauthorizedUrlIfNecessary(filter);
    }

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

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

            }
        }
    }
}

 

 

三、FilterRegistrationBean:上面两步已经将BeanName为shiroFilter的SpringShiroFilter注入到了Spring容器中,现在来说一下是如何从Spring容器中注册到Servlet容器中的。

一般我们在Spring中配置Filter是这样写的:

@Configuration
public class FilterConfig {
    /**
     * 注册DelegatingFilterProxy(Shiro)
     *
     * @return
     * @author 
     * @create 2020年8月19日
     */
    @Bean
    public FilterRegistrationBean shiroFilterRegistrationBean () {
        FilterRegistrationBean filterRegistration = new FilterRegistrationBean();
        filterRegistration.setFilter(new DelegatingFilterProxy("shiroFilter"));
        //  该值缺省为false,表示生命周期由SpringApplicationContext管理,设置为true则表示由ServletContainer管理
        filterRegistration.addInitParameter("targetFilterLifecycle", "true");
        filterRegistration.setEnabled(true);
        filterRegistration.addUrlPatterns("/*");
        return filterRegistration;
    }
}

 

 他具体的工作原理是什么?

1、Spring容器在启动时会调用org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext的selfInitialize(ServletContext servletContext)方法。
    private void selfInitialize(ServletContext servletContext) throws ServletException {
        this.prepareWebApplicationContext(servletContext);
        this.registerApplicationScope(servletContext);
        WebApplicationContextUtils.registerEnvironmentBeans(this.getBeanFactory(), servletContext);
        Iterator var2 = this.getServletContextInitializerBeans().iterator();

        while(var2.hasNext()) {
            ServletContextInitializer beans = (ServletContextInitializer)var2.next();
            beans.onStartup(servletContext);
        }

    }

 

 2、bean.onStartup(servletContext)调用 RegistrationBean.onStartup()方法,该方法又调用抽象方法register()。

 public final void onStartup(ServletContext servletContext) throws ServletException {
        String description = this.getDescription();
        if (!this.isEnabled()) {
            logger.info(StringUtils.capitalize(description) + " was not registered (disabled)");
        } else {
            this.register(description, servletContext);
        }
    }

 protected abstract void register(String description, ServletContext servletContext);

3、register()方法由RegistrationBean的子类DynamicRegistrationBean实现,并调用由子类AbstractFilterRegistrationBean实现的addRegistration()方法。

  protected final void register(String description, ServletContext servletContext) {
        D registration = this.addRegistration(description, servletContext);
        if (registration == null) {
            logger.info(StringUtils.capitalize(description) + " was not registered (possibly already registered?)");
        } else {
            this.configure(registration);
        }
    }

    protected abstract D addRegistration(String description, ServletContext servletContext);

 

 4、AbstractFilterRegistrationBean的addRegistration()方法,向ServletContext中注册了一个过滤器。而这个过滤器是子类提供的,也就是我们在Spring中注入的FilterRegistrationBean提供的,他的getFilter()方法

返回的就是我们的shiroFilter 。

AbstractFilterRegistrationBean:

   protected Dynamic addRegistration(String description, ServletContext servletContext) {
        //调用子类实现的抽象方法
        Filter filter = this.getFilter();
        //向servletContext中注册Filter
        return servletContext.addFilter(this.getOrDeduceName(filter), filter);
    }
    //这个方法由子类实现
    public abstract T getFilter();

FilterRegistrationBean:

public class FilterRegistrationBean<T extends Filter> extends AbstractFilterRegistrationBean<T> {
    private T filter;

    public FilterRegistrationBean() {
        super(new ServletRegistrationBean[0]);
    }

    public FilterRegistrationBean(T filter, ServletRegistrationBean<?>... servletRegistrationBeans) {
        super(servletRegistrationBeans);
        Assert.notNull(filter, "Filter must not be null");
        this.filter = filter;
    }

    public T getFilter() {
        return this.filter;
    }

    public void setFilter(T filter) {
        Assert.notNull(filter, "Filter must not be null");
        this.filter = filter;
    }
}

 

 

至此,shiroFilter从Spring容器中注册到了Servlet容器中了。

标签:return,SpringBoot,SpingBoot,filter,servletContext,new,shiroFilter,public,String
来源: https://www.cnblogs.com/jqws/p/14793992.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有