0.数据库原型
数据库原型如下图所示:
1.引入jar
除在入门中引入的jar包之外,在web项目中如果用到shiro,还需要引入以下jar:
shiro-web-1.2.3.jar
shiro-spring-1.2.3.jar
shiro-quartz-1.2.3.jar
quartz-1.6.1.jar
ehcache-core-2.5.0.jar
shiro-ehcache-1.2.3.jar
2.在web.xml中配置shiro的filter
在web项目中也通过filter(过滤器)拦截shiro,filter拦截后将操作权交给在spring.xml中配置的过滤器链(fliterchain)处理,shiro中提供许多过滤器。在web.xml中配置shiro过滤器的web.xml完整代码如下:
1 | <?xml version="1.0" encoding="UTF-8"?> |
3. 在spring-shiro.xml中配置web.xml中过滤器对应spring容器中的bean.
配置代码如下:
1 | <beans xmlns="http://www.springframework.org/schema/beans" |
我把自定义realm也放在了这一步进行配置
4.自定义realm进行认证
我们在上一步spring-shiro.xml中配置了loginUrl,当用户没有登录时将会请求此地址进行登录,FormAuthenticationFilter会拦截到用户的请求,获取到username,password(默认,可以进行配置),之后调用我们自定义的Realm进行认证。自定义realm代码如下:
1 | /** |
在这里要注意的是:我们从token中获取到的是用户输入请求过来的用户名和密码,然后根据用户名查询数据库获得的用户信息并封装成ActiveUser,放在SimpleAuthenticationInfo中,之后ActiveUser就是主体的身份信息而不是username(你在SimpleAuthenticationInfo把谁放进去了,谁就是主体的身份信息)。
5.自定义Realm进行授权
直接入正题,我们这里采用注解进行springmvc的授权操作,注解中填权限标识符。首先需要在spring-mvc.xml中配置对shiro注解的支持。在原有spring-mvc.xml的代码中加入以下配置:
1 | <!-- 开启aop,对类代理 --> |
在请求的Controller方法中配置@RequiresPermissions注解(里面填权限标识符),示例代码如下:
1 | //商品信息方法 |
比如当请求/queryItem过来时,看到有RequiresPermissions注解,表明本请求需要要权限才能访问,就会调用自定义的realm查询本主体(subject)所有的权限,看这个权限标识符是否在该主体拥有的权限标识符中,自定义realm进行授权代码如下:
1 | /** |
6.常用的shiro过滤器
常用的shiro过滤器如下,可以关联源码,在shiro-web包下查看源代码:
| 过滤器简称 | 对应的java类 |
| ———- | —————————————- |
| anon | org.apache.shiro.web.filter.authc.AnonymousFilter |
| authc | org.apache.shiro.web.filter.authc.FormAuthenticationFilter |
| authcBasic | org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter |
| perms | org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter |
| port | org.apache.shiro.web.filter.authz.PortFilter |
| rest | org.apache.shiro.web.filter.authz.HttpMethodPermissionFilter |
| roles | org.apache.shiro.web.filter.authz.RolesAuthorizationFilter |
| ssl | org.apache.shiro.web.filter.authz.SslFilter |
| user | org.apache.shiro.web.filter.authc.UserFilter |
| logout | org.apache.shiro.web.filter.authc.LogoutFilter |
anon:例子/admins/=anon 没有参数,表示可以匿名使用。
authc:例如/admins/user/=authc表示需要认证(登录)才能使用,FormAuthenticationFilter是表单认证,没有参数
perms:例子/admins/user/*=perms[user:add:],参数可以写多个,多个时必须加上引号,并且参数之间用逗号分割,例如/admins/user/=perms[“user:add:,user:modify:“],当有多个参数时必须每个参数都通过才通过,想当于isPermitedAll()方法。
user:例如/admins/user/**=user没有参数表示必须存在用户, 身份认证通过或通过记住我认证通过的可以访问,当登入操作时不做检查
7.Jsp标签授权
在jsp或者html页面中,如果开发者想对项目控制的粒度更加精细,可以在页面中使用标签授权(类似于ifelse的判断形式),Jsp页面添加:
1 | <%@ tagliburi="http://shiro.apache.org/tags" prefix="shiro" %> |
标签名称 | 标签条件(均是显示标签内容) |
---|---|
shiro:authenticated(左右两边的尖括号省略) | 登录之后 |
shiro:notAuthenticated | 不在登录状态时 |
shiro:guest | 用户在没有RememberMe时 |
shiro:user | 用户在RememberMe时 |
shiro:hasAnyRoles name=”abc,123” | 在有abc或者123角色时 |
shiro:hasRole name=”abc” | 拥有角色abc |
shiro:lacksRole name=”abc” | 没有角色abc |
shiro:hasPermission name=”abc” | 拥有权限资源abc |
shiro:lacksPermission name=”abc” | 没有abc权限资源 |
shiro:principal | 显示用户身份()名称 |
到这里其实shiro跟web项目的整合已经配置完成了,正常使用是没有问题的,下面涉及到的都是优化的操作
8.shiro缓存
通过上一步打断点我们会看出,只要用户发请求了,而且controller中有RequiresPermissions注解了,都会重复调用自定义realm的授权方法,重复的查询数据库,我们就想到了用缓存来提高速度。
shiro中提供了对认证信息和授权信息的缓存。shiro默认是关闭认证信息缓存的,对于授权信息的缓存shiro默认开启的。主要研究授权信息缓存,因为授权的数据量大。
用户认证通过。
该用户第一次授权:调用realm查询数据库
该用户第二次授权:不调用realm查询数据库,直接从缓存中取出授权信息(权限标识符)。
添加ehcache的jar,并且配置shiro-ehcache.xml,代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
<!--diskStore:缓存数据持久化的目录 地址 -->
<diskStore path="F:\develop\ehcache" />
<defaultCache
maxElementsInMemory="1000"
maxElementsOnDisk="10000000"
eternal="false"
overflowToDisk="false"
diskPersistent="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU">
</defaultCache>
</ehcache>在spring-shiro.xml配置文件中,配置安全管理器(securityManger)中引入shiro-ehcache.xml:
1
2
3
4
5
6
7
8
9
10
11<!-- securityManager安全管理器 -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="customRealm" />
<!-- 注入缓存管理器 -->
<property name="cacheManager" ref="cacheManager"/>
</bean>
<!-- 缓存管理器 -->
<bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
<property name="cacheManagerConfigFile" value="classpath:shiro-ehcache.xml"/>
</bean>清空缓存:
如果用户正常退出,缓存自动清空。
如果用户非正常退出,缓存自动清空。
如果修改了用户的权限,而用户不退出系统,修改的权限无法立即生效。
需要手动进行编程实现:在权限修改后调用自定义realm的clearCache方法清除缓存。
在自定义Realm定义的清空缓存的方法如下:1
2
3
4
5//清除缓存
public void clearCached() {
PrincipalCollection principals = SecurityUtils.getSubject().getPrincipals();
super.clearCache(principals);
}
在修改完用户的权限之后的serviceImpl层中可以直接调用清除缓存:
1 | //注入realm |
9.自定义表单认证过滤器
现在有一个需求,就是用户登录时不止提交有用户名,密码,还有验证码。那么原有的表单验证拦截器只验证用户名和密码就不行了。我们继承FormAuthenticationFilter拦截器实现自己的拦截器即可。代码如下:
1 | package com.catchu.ssm.shiro; |
在spring-shiro.xml中配置代码如下:
1 | <!-- 自定义form认证过虑器 --> |
注入到安全管理器(securitymanager)
1 | <!-- 自定义filter配置 --> |
10.配置rememberMe
有时用户登录之后需要记住用户名和密码,保存在cookie中,下次登录可以直接访问。
jsp中页面代码如下:
1
2
3
4<tr>
<TD></TD>
<td><input type="checkbox" name="rememberMe" />自动登陆</td>
</tr>ActiveUser类要实现序列化(用户身份信息,存入session 由于tomcat将session会序列化在本地硬盘上,所以使用Serializable接口):
1
2
3
4
5public class ActiveUser implements java.io.Serializable {
private String userid;//用户id(主键)
private String usercode;// 用户账号
private String username;// 用户名称
}spring-shiro.xml中配置rememberMeManager管理器
1
2
3
4
5
6
7
8
9
10
11<!-- rememberMeManager管理器,写cookie,取出cookie生成用户信息 -->
<bean id="rememberMeManager" class="org.apache.shiro.web.mgt.CookieRememberMeManager">
<property name="cookie" ref="rememberMeCookie" />
</bean>
<!-- 记住我cookie -->
<bean id="rememberMeCookie" class="org.apache.shiro.web.servlet.SimpleCookie">
<!-- rememberMe是cookie的名字 -->
<constructor-arg value="rememberMe" />
<!-- 记住我cookie生效时间30天 -->
<property name="maxAge" value="2592000" />
</bean>使用UserFilter
如果设置记住我,下次访问某些url时可以不用登陆。将记住我即可访问的地址配置让UserFilter拦截。在spring-shiro.xml中配置如下:1
2
3
4<!-- 配置记住我或认证通过可以访问的地址 -->
/index.jsp = user
/first.action = user
/welcome.jsp = user
都配置完成之后,在浏览器的cookie中查看即可看到cookie信息。
附:spring-shiro.xml中所有配置如下:
1 | <beans xmlns="http://www.springframework.org/schema/beans" |
热评话题