Spring整合Shiro,Controller如果使用了Shiro的注解则没有注册Mapping的问题

红薯官方 发布于 2017/02/08 09:56
阅读 1K+
收藏 2

Controller

@Controller("/")
public class IndexController {

    //@RequiresUser // 一旦加上这个就没有在日志打印中看到注册Controller方法
    @RequestMapping("/hello.do")
    @ResponseBody
    public String hello() {
        return "Hello Spring MVC";
    }

    @RequestMapping("/home.do")
    @ResponseBody
    public String home() {
        return "Home page! ";
    }
}

正常注册Controller的日志:

org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping.register Mapped "{[/home.do]}" onto public java.lang.String com.rocbin.springmvc.controller.IndexController.home()
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping.register Mapped "{[/hello.do]}" onto public java.lang.String com.rocbin.springmvc.controller.IndexController.hello()

而反注释了@RequiresUser注解之后,重启服务就看不到上面的日志打印,访问也出现404。

我使用JRebel来热更新代码,随意改动一下Controller中间的代码之后,JRebel打印如下的日志:

JRebel打印日志:

org.springframework.web.servlet.PageNotFound.noHandlerFound No mapping found for HTTP request with URI [/home.do] in DispatcherServlet with name 'springmvc'
JRebel: Reloading class 'com.rocbin.springmvc.controller.IndexController'.
JRebel: Reinitialized class 'com.rocbin.springmvc.controller.IndexController$$EnhancerBySpringCGLIB$$c011bd8c'.

正常来说,JRebel还会打印到SpringMVC重新刷新此Controller 映射的日志的。
很诡异吧,是不是因为被EnhancerBySpringCGLIB这个AOP代理过导致的呢?使用了Shiro的注解之后这个Controller就无法访问了。

百度了“spring shiro controller无效”也有比较多的人遇到这个问题,但没看明白为什么会出现这个问题。

昨天花了一天没解决,现在正在继续研究中,有知道的朋友麻烦指点下,谢谢。

加载中
0
红薯官方
红薯官方

问题已找到,查看了ShiroFilterFactoryBean中的源码,发现filterChainDefinitions配置属性是通过INI解析然后调用

setFilterChainDefinitionMap(Map<String, String> filterChainDefinitionMap)

而filterChainDefinitionMap配置属性也是直接调用此方法,后者覆盖了前者,将URL拦截定义给覆盖了!

去掉了后面这段map设置问题暂时解决。

ShiroFilterFactoryBean部分源码

    public void setFilterChainDefinitionMap(Map<String, String> filterChainDefinitionMap) {
        this.filterChainDefinitionMap = filterChainDefinitionMap;
    }

    public void setFilterChainDefinitions(String definitions) {
        Ini ini = new Ini();
        ini.load(definitions);
        Section section = ini.getSection("urls");
        if(CollectionUtils.isEmpty(section)) {
            section = ini.getSection("");
        }

        this.setFilterChainDefinitionMap(section);
    }

这都是个坑啊,RBAC是否要这样自己定义一个Filter?感觉非也。

0
Kit_lee
Kit_lee

不好说,需要把配置发出来才好判断

0
红薯官方
红薯官方

怀疑是代理引起的问题,参考了开涛的博客,把下面的代码换成后面的代码:

    <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
          depends-on="lifecycleBeanPostProcessor"/>
    <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
        <property name="securityManager" ref="securityManager"/>
    </bean>
    <aop:config proxy-target-class="true"/>
    <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
        <property name="securityManager" ref="securityManager"/>
    </bean>

这样之后,使用注解可以正常拦截请求了!也不会出现上面的问题的。

但不知道为何,不加注解的,还是拦截不到。

-----------------------

Shiro URL拦截的配置:

    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <property name="securityManager" ref="securityManager"/>
        <property name="loginUrl" value="/hello.do"/>
        <property name="unauthorizedUrl" value="/403.jsp"/>
        <property name="successUrl" value="/home.do"/>
        <property name="filterChainDefinitions">
            <value>
                /hello.do = user
                /pay.do = user
                /*.jsp = anon
                /passport/login.do = anon
                /passport/logout.do = user
                /static/** = anon
                /** = rbac
            </value>
        </property>
        <property name="filterChainDefinitionMap">
            <map>
                <entry key="rbac" value="rbacFilter"></entry>
            </map>
        </property>
    </bean>

/pay.do却能被未登录的身份访问!

试着把@RequiredUser注解去掉,重启服务,/hello.do也未被拦截权限,和/pay.do一样可以访问,shiro起不到作用了。

shiroFilter在web.xml中配置是最前的filter,拦截的是/*。

 

0
红薯官方
红薯官方

总结下,一是要注意AOP的配置方式,二要注意filterChainDefinitions与filterChainDefinitionMap不能同时配置,会有冲突。

基于URL拦截和注解拦截,同时配置两者时,注解的优先级更高,如/home.do = user,而在home()方法之上配置了Shiro注解@RequireGuest是,前者配置无效,/home.do可以被匿名访问!

整合的过程中参考了开涛的博客《跟我学Shiro》,在此表示感谢。

返回顶部
顶部