`

146. Spring Boot Shiro无法访问JS/CSS/IMG+自定义Filter无法访问完美方案【从零开始学Spring Boot】

阅读更多

 

  

     今天2017910日,是教师节,在此感谢老师,祝老师节日快乐。我在我的学生生涯中遇到了好几个对我特别好的老师,真的很感谢他们,因为有你们,所以我们成长

需求缘起

       有网友说:无法访问到JS/CSS/IMG,其实这个问题,对于使用过Shiro的特别好解决,只需要做简单的配置就可以搞定了,但是对于Shiro不了解的,那么可能就需要求助了。哈哈,同一个问题回答多了,耳朵也会长茧的。好了,本篇博客就是为了解决这个问题。

 

1JS/CSS/IMGshiro拦截

       我们请求spring boot的静态资源被shiro过滤器拦截了,那么我想我直接让shiro放行就可以了,也就是css:annoimg:annojs:anno,转换为shiro代码就是:

 

 

ShiroFilterFactoryBean shiroFilterFactoryBean  = new ShiroFilterFactoryBean();
filterChainDefinitionMap.put("/img/**", "anon");//img       
filterChainDefinitionMap.put("/js/**", "anon");//js
filterChainDefinitionMap.put("/css/**", "anon");//css
 

 

 

 

2)自定义Filter导致无法访问

       如果添加了上面的配置,还无法使用的,那么就看看是否是如下这种情况引起的:

ShiroConfiguration中如果您有这么一段自定义Filter的代码:

 

    @Bean
    public CustomFormAuthenticationFilter formAuthenticationFilter(){
       CustomFormAuthenticationFilter customFormAuthenticationFilter = new CustomFormAuthenticationFilter();
       return customFormAuthenticationFilter;
    }
 

 

       这样注入Filter的方式也是会出现JS/CSS/IMG无法访问的,这是为什么呢?

这是因为:容器把自定义的CustomFormAuthenticationFilter也作为容器的filter接管,所有的请求又都经过一次filter,那么就会导致一个问题出现:比如:我们定义 /js/**=anon,/css/**=anon, /img/ =anno,那么所有JS/CSS/IMG等资源文件也会被拦截。也就是说:我们自定义的CustomFormAuthenticationFiltershiroFilter不再是上下级的关系了,而是平级的关系,由SpringApplicationFilterConfig一起管理了。

       那也就是说:我们只需要修改为上下级的关系就可以了。

首先,我们就不能CustomFormAuthenticationFilterSpring管理了,先去掉注解@Bean

       第二就是:使用ShiroFilterFactoryBean进行注入,就是上下级的关系了,核心代码部分:

 

     

ShiroFilterFactoryBean shiroFilterFactoryBean  = new ShiroFilterFactoryBean();
//自定义filter.
Map<String,Filter> filters  = new HashMap<String,Filter>();
CustomFormAuthenticationFilter formAuthenticationFilter =  new CustomFormAuthenticationFilter();//初始化自定义的filter.
filters.put("authc", formAuthenticationFilter);//添加到map中.
shiroFilterFactoryBean.setFilters(filters);//交给spring shiroFilter管理

 

 

 

3)问题2方案导致新问题

       我们使用了new CustomFormAuthenticationFilter()的方式就无法使用spring的特性,在CustomFormAuthenticationFilter的类中就不能使用@Autowire注入别的service进行使用了。所以这里就存在了新的问题了,由不能直接使用@Bean的方式注入,那么怎么解决呢?

       我们会思考是否有一种方式注册我们自定义的FilterSpring容器中,但是又不添加FilterFilterChain中呢?所以我们的问题也就是:怎么取消    Filter自动注册?

       Spring BootFilterServlet提供了相应的注册类,来进行精细化的配置,我们可以使用注册类来取消Filter的自动注册。通过使用FilterRegistrationBean来进行Filter的注册,同时,设置enabledfalse,就可以取消Filter的自动注册行为了。可以参考文档:Spring Boot Document

       具体怎么操作呢?

    @Bean
    public CustomFormAuthenticationFilter customFormAuthenticationFilter(){
       System.out.println("ShiroConfiguration.formAuthenticationFilter()");
       CustomFormAuthenticationFilter customFormAuthenticationFilter = new CustomFormAuthenticationFilter();
       return customFormAuthenticationFilter;
    }
 
    @Bean
    public FilterRegistrationBean registrationBean(CustomFormAuthenticationFilter customFormAuthenticationFilter){
       System.out.println("AppcustomFormAuthenticationFilter()");
       FilterRegistrationBean registration = new FilterRegistrationBean(customFormAuthenticationFilter);
        registration.setEnabled(false);//怎么取消  Filter自动注册,不会添加到FilterChain中.
        return registration;
    }

 

       这里还是使用@Bean注入CustomFormAuthenticationFilter,但是在自动注入之后使用FilterRegistrationBean对其重新进行了设置,取消自动注册功能。这里容易犯错的地方就是CustomFormAuthenticationFilter不使用@Bean注入了,如果是这样的话,就会发现是先shiro的配置先注入,CustomFormAuthenticationFilter还没注入就无法找到了。

 

à悟空学院:https://t.cn/Rg3fKJD

学院中有Spring Boot相关的课程!点击「阅读原文」进行查看!

SpringBoot视频:http://t.cn/A6ZagYTi

Spring Cloud视频:http://t.cn/A6ZagxSR

SpringBoot Shiro视频:http://t.cn/A6Zag7IV

SpringBoot交流平台:https://t.cn/R3QDhU0

SpringData和JPA视频:http://t.cn/A6Zad1OH

SpringSecurity5.0视频:http://t.cn/A6ZadMBe

Sharding-JDBC分库分表实战http://t.cn/A6ZarrqS

分布式事务解决方案「手写代码」:http://t.cn/A6ZaBnIr 

分享到:
评论
6 楼 林祥纤 2018-11-05  
javazhy 写道
你好,最近在弄这个springboot+shiro的整合,现在静态资源的匿名访问都配置了,我在static下面又建了一层statics,然后这么配置,访问加载静态资源的时候一直405,请帮忙回复下是什么问题,谢谢 filterChainDefinitionMap.put("/statics/ace/**", "anon");


这样看,看不出来,方便把源码提供下嘛??
5 楼 javazhy 2018-11-01  
你好,最近在弄这个springboot+shiro的整合,现在静态资源的匿名访问都配置了,我在static下面又建了一层statics,然后这么配置,访问加载静态资源的时候一直405,请帮忙回复下是什么问题,谢谢 filterChainDefinitionMap.put("/statics/ace/**", "anon");
4 楼 林祥纤 2018-03-13  
jack_zou 写道
你好,请问下我spring boot配置成这样,怎么js,css能匿名访问,img,fonts目录下不行?
    @Bean("shiroFilter")
    public ShiroFilterFactoryBean factory(DefaultWebSecurityManager securityManager) {
        ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();

        // 添加自己的过滤器并且取名为jwt
        Map<String, Filter> filterMap = new HashMap<>();
        filterMap.put("jwt", new JWTFilter());
//        filterMap.put("systemLogout", new SystemLogoutFilter());
        factoryBean.setFilters(filterMap);

        factoryBean.setSecurityManager(securityManager);
// 要求登录时的链接(可根据项目的URL进行替换),非必须的属性,默认会自动寻找Web工程根目录下的"/login.jsp"页面
        factoryBean.setLoginUrl("/login");
// 登录成功后要跳转的连接,逻辑也可以自定义,例如返回上次请求的页面
// factoryBean.setSuccessUrl("/user-list");
// 用户访问未对其授权的资源时,所显示的连接
        factoryBean.setUnauthorizedUrl("/login");

        /*
         * 自定义url规则
         * http://shiro.apache.org/web.html#urls-
         */
        Map<String, String> filterRuleMap = new HashMap<>();
       
        filterRuleMap.put("logout", "logout");
// <!-- 过滤链定义,从上向下顺序执行,一般将 /**放在最为下边 -->:这是一个坑呢,一不小心代码就不好使了;
// <!-- authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问-->
filterRuleMap.put("/css/**", "anon");
filterRuleMap.put("/js/**", "anon");
filterRuleMap.put("/img/**", "anon");
filterRuleMap.put("/fonts/**", "anon");
filterRuleMap.put("/assets/**", "anon");
filterRuleMap.put("/custom/**", "anon");
filterRuleMap.put("/login", "anon");


        // 所有请求通过我们自己的JWT Filter
        filterRuleMap.put("/**", "jwt");
        factoryBean.setFilterChainDefinitionMap(filterRuleMap);
        return factoryBean;
    }


应该可以的,不行你配置一个:
filterRuleMap.put("/static/fonts/**", "anon");

3 楼 jack_zou 2018-03-13  
你好,请问下我spring boot配置成这样,怎么js,css能匿名访问,img,fonts目录下不行?
    @Bean("shiroFilter")
    public ShiroFilterFactoryBean factory(DefaultWebSecurityManager securityManager) {
        ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();

        // 添加自己的过滤器并且取名为jwt
        Map<String, Filter> filterMap = new HashMap<>();
        filterMap.put("jwt", new JWTFilter());
//        filterMap.put("systemLogout", new SystemLogoutFilter());
        factoryBean.setFilters(filterMap);

        factoryBean.setSecurityManager(securityManager);
// 要求登录时的链接(可根据项目的URL进行替换),非必须的属性,默认会自动寻找Web工程根目录下的"/login.jsp"页面
        factoryBean.setLoginUrl("/login");
// 登录成功后要跳转的连接,逻辑也可以自定义,例如返回上次请求的页面
// factoryBean.setSuccessUrl("/user-list");
// 用户访问未对其授权的资源时,所显示的连接
        factoryBean.setUnauthorizedUrl("/login");

        /*
         * 自定义url规则
         * http://shiro.apache.org/web.html#urls-
         */
        Map<String, String> filterRuleMap = new HashMap<>();
       
        filterRuleMap.put("logout", "logout");
// <!-- 过滤链定义,从上向下顺序执行,一般将 /**放在最为下边 -->:这是一个坑呢,一不小心代码就不好使了;
// <!-- authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问-->
filterRuleMap.put("/css/**", "anon");
filterRuleMap.put("/js/**", "anon");
filterRuleMap.put("/img/**", "anon");
filterRuleMap.put("/fonts/**", "anon");
filterRuleMap.put("/assets/**", "anon");
filterRuleMap.put("/custom/**", "anon");
filterRuleMap.put("/login", "anon");


        // 所有请求通过我们自己的JWT Filter
        filterRuleMap.put("/**", "jwt");
        factoryBean.setFilterChainDefinitionMap(filterRuleMap);
        return factoryBean;
    }
2 楼 林祥纤 2017-09-12  
lixuejian 写道
    


1 楼 lixuejian 2017-09-11  
    

相关推荐

Global site tag (gtag.js) - Google Analytics