shiro是一个非常强大灵活的权限控制框架,属于apache的顶级项目.springrain使用shiro实现了权限控制功能.
归根到底,权限控制无非是利用过滤器控制访问的认证和授权,shiro也不例外.我们来看看shiro是怎么实现的吧.

要在web中使用shiro,总共分三步:

第一步:在web.xml中配置shiro的过滤器

建议是应用的第一个过滤器,springrain示例配置如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
<filter>
<filter-name>shiroFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<init-param>
<param-name>targetFilterLifecycle</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>shiroFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
<dispatcher>INCLUDE</dispatcher>
<dispatcher>ERROR</dispatcher>
</filter-mapping>

这个shiroFilter其实是个spring bean,等下会重点说这个bean,dispatcher这个标签是为了在forward和redirect的情况下也需要经过过滤器

第二步:配置spring-shiro

springrain配置是applicationContext-shiro.xml

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
<!-- 权限管理器 -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<!-- 数据库认证的实现 org.springrain.frame.shiro.ShiroDbRealm -->
<property name="realm" ref="shiroDbRealm" />
<!-- session 管理器 -->
<property name="sessionManager" ref="sessionManager" />
<!-- 缓存管理器 -->
<property name="cacheManager" ref="shiroCacheManager" />
</bean>
<!-- session管理器 -->
<bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
<!-- 超时时间 -->
<property name="globalSessionTimeout" value="1800000"/>
<!-- session存储的实现 -->
<property name="sessionDAO" ref="shiroSessionDao"/>
<!-- sessionIdCookie的实现,用于重写覆盖容器默认的JSESSIONID -->
<property name="sessionIdCookie" ref="sharesession"/>
<!-- 定时检查失效的session -->
<property name="sessionValidationSchedulerEnabled" value="true" />
</bean>

<!-- sessionIdCookie的实现,用于重写覆盖容器默认的JSESSIONID -->
<bean id="sharesession" class="org.apache.shiro.web.servlet.SimpleCookie">
<!-- cookie的name,对应的默认是 JSESSIONID -->
<constructor-arg name="name" value="SHAREJSESSIONID"/>
</bean>
<!-- session存储的实现 -->
<bean id="shiroSessionDao" class="org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO" />

<!-- 缓存管理实现 -->
<bean id="shiroCacheManager" class="org.apache.shiro.cache.MemoryConstrainedCacheManager" />

<!-- shiro的主过滤器,beanId 和web.xml中配置的filter name需要保持一致 -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"
depends-on="frameperms">
<!-- 安全管理器 -->
<property name="securityManager" ref="securityManager" />
<!-- 默认的登陆访问url -->
<property name="loginUrl" value="/login" />
<!-- 登陆成功后跳转的url -->
<property name="successUrl" value="/index" />
<!-- 没有权限跳转的url -->
<property name="unauthorizedUrl" value="/unauth" />
<!-- 访问地址的过滤规则,从上至下的优先级,如果有匹配的规则,就会返回,不会再进行匹配 -->
<property name="filterChainDefinitions">
<value>
/js/** = anon
/css/** = anon
/images/** = anon
/myimg/**= anon
/unauth = anon
/getCaptcha=anon
/login = anon
/favicon.ico = anon
/index = user
/logout = logout
/menu/leftMenu=user
/**/ajax/** = user
/** = user,frameperms
</value>
</property>
<!-- 声明自定义的过滤器 -->
<property name="filters">
<map>
<entry key="frameperms" value-ref="frameperms"></entry>
</map>
</property>
</bean>
<!-- 起效权限注解,这个很少在web项目中用到,一般是控制url的访问,不是在controller中声明权限注解 -->
<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />

frameperms是自定义的过滤器,除了那些特殊url,其他的菜单都在数据库,查询用户权限判断,下一篇文章介绍下权限相关的表结构.
另外不建议在web项目使用类似 admin:user:edit这种方式控制权限,这种方式等同给url又起了一个别名,这样虽然看起来比较容易理解,但是相当死板和麻烦.建议直接使用url判断权限.
authc 和 user的区别是 user包含 rememberme,authc不包含,就这一点区别.

第三步:实现数据库认证和权限过滤

数据库认证shiroDbRealm的代码

自定义权限过滤frameperms的代码

另外 springrain 没有使用authc实现登陆,而是使用一个普通的controller方法进行登陆 org.springrain.frame.controller.BaseController.loginPost(User, HttpSession, Model, HttpServletRequest)

1
2
3
//会调用 shiroDbRealm 的认证方法
//org.springrain.frame.shiro.ShiroDbRealm.doGetAuthenticationInfo(AuthenticationToken)
user.login(token);