授权管理
1.HTML授权
在菜单页面中只显示当前用户拥有权限操作的菜单
shiro标签
<!--guest判断用户是否是游客身份,是则显示此标签内容-->
<shiro:guest>
游客:<a href="login.html">登录</a>
</shiro:guest>
<!--user判断用户是否是认证身份,是则显示-->
<shiro:user>
<!--principal获取当前登录用户名-->
用户【<shiro:principal/>】欢迎您
<!-- hasRole获取用户角色-->
当前用户为<shiro:hasRole name="admin">超级管理员</shiro:hasRole>
订单管理
<!-- hasPermission当前用户有权限则显示-->
<shiro:hasPermission name="sys:x:save"><a href="#">添加订单</a></shiro:hasPermission>
</shiro:user>
2.过滤器授权
在shiro过滤器中对请求的url进行权限设置
filterMap.put("/c_add.html","perms[sys:c:save]");
//设置未授权访问的页面路径,当权限不足时显示此页面
filter.setUnauthorizedUrl("/lesspermission.html");
3.注解授权
配置Spring对Shiro注解的支持
@Bean
public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator(){
DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator();
creator.setProxyTargetClass(true);
return creator;
}
@Bean
public AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager){
AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
advisor.setSecurityManager(securityManager);
return advisor;
}
在请求的控制器添加权限注解
@RequiresPermissions("sys:k:find")
@RequiresRoles("")
通过全局异常处理,指定权限不足时的页面跳转
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler
public String doException(Exception e){
if (e instanceof AuthorizationException){
return "lesspermission";
}
return null;
}
}
缓存使用
使用shiro进行权限管理过程中,每次授权都会访问realm中的doGetAuthorizationInfo方法查询当前用户的角色及权限信息,如果系统的用户量比较大则会对数据库造成压力
shiro支持缓存以降低对数据库的访问压力(缓存的是授权信息)
1.导入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>1.5.3</version>
</dependency>
2.配置缓存策略
resoures目录下创建ehcache.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
updateCheck="false">
<!--
diskStore:为缓存路径,ehcache分为内存和磁盘两级,此属性定义磁盘的缓存位置。参数解释如下:
user.home – 用户主目录
user.dir – 用户当前工作目录
java.io.tmpdir – 默认临时文件路径
-->
<diskStore path="java.io.tmpdir/Tmp_EhCache"/>
<!--
defaultCache:默认缓存策略,当ehcache找不到定义的缓存时,则使用这个缓存策略。只能定义一个。
-->
<!--
name:缓存名称。
maxElementsInMemory:缓存最大数目
maxElementsOnDisk:硬盘最大缓存个数。
eternal:对象是否永久有效,一但设置了,timeout将不起作用。
overflowToDisk:是否保存到磁盘,当系统当机时
timeToIdleSeconds:设置对象在失效前的允许闲置时间(单位:秒)。仅当eternal=false对象不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大。
timeToLiveSeconds:设置对象在失效前允许存活时间(单位:秒)。最大时间介于创建时间和失效时间之间。仅当eternal=false对象不是永久有效时使用,默认是0.,也就是对象存活时间无穷大。
diskPersistent:是否缓存虚拟机重启期数据 Whether the disk store persists between restarts of the Virtual Machine. The default value is false.
diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。
diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。
memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。
clearOnFlush:内存数量最大时是否清除。
memoryStoreEvictionPolicy:可选策略有:LRU(最近最少使用,默认策略)、FIFO(先进先出)、LFU(最少访问次数)。
FIFO,first in first out,这个是大家最熟的,先进先出。
LFU, Less Frequently Used,就是上面例子中使用的策略,直白一点就是讲一直以来最少被使用的。如上面所讲,缓存的元素有一个hit属性,hit值最小的将会被清出缓存。
LRU,Least Recently Used,最近最少使用的,缓存的元素有一个时间戳,当缓存容量满了,而又需要腾出地方来缓存新的元素的时候,那么现有缓存元素中时间戳离当前时间最远的元素将被清出缓存。
-->
<defaultCache
name="defaultCache"
eternal="false"
maxElementsInMemory="10000"
overflowToDisk="false"
diskPersistent="false"
timeToIdleSeconds="1800"
timeToLiveSeconds="259200"
memoryStoreEvictionPolicy="LRU"/>
<cache
name="users"
eternal="false"
maxElementsInMemory="5000"
overflowToDisk="false"
diskPersistent="false"
timeToIdleSeconds="1800"
timeToLiveSeconds="1800"
memoryStoreEvictionPolicy="LRU"/>
</ehcache>
3.加入缓存管理
ShiroConfig.java
@Bean
public EhCacheManager getEhCacheManager(){
EhCacheManager ehCacheManager = new EhCacheManager();
ehCacheManager.setCacheManagerConfigFile("classpath:ehcache.xml");
return ehCacheManager;
}
@Bean
public DefaultWebSecurityManager getDefaultWebSecurityManager(MyRealm myRealm){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(myRealm);
securityManager.setCacheManager(getEhCacheManager());
return securityManager;
}
3.session管理
shiro进行认证和授权是基于session实现的,shiro包含了对session的管理
如果我们需要对session进行管理
- 自定义session管理器
- 将自定义session管理器设置给SecurityManager
@Bean
public DefaultWebSessionManager getDefaultWebSessionManager(){
DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
sessionManager.setGlobalSessionTimeout(5*60*1000);
return sessionManager;
}
@Bean
public DefaultWebSecurityManager getDefaultWebSecurityManager(MyRealm myRealm){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(myRealm);
securityManager.setCacheManager(getEhCacheManager());
securityManager.setSessionManager(getDefaultWebSessionManager());
return securityManager;
}
4.RememberMe
将用户的访问权限分为三个级别
1.未认证 可访问的页面
2.记住我 可访问的页面
3.已认证 可访问的页面
1.在过滤器中设置“记住我”可访问的url
/*设置shiro的拦截规则
anon 匿名用户可访问
authc 认证用户可访问
user 使用RemeberMe的用户可访问
perms 对应权限可访问
logout 指定退出的url
role 对应角色可访问
*/
Map<String,String> filterMap=new HashMap<>();
filterMap.put("/", "anon");
filterMap.put("/login.html", "anon");
filterMap.put("/regist.html", "anon");
filterMap.put("/user/login", "anon");
filterMap.put("user/regist", "anon");
filterMap.put("/static/**", "anon");
filterMap.put("/**", "authc");
filterMap.put("/c_add.html", "perms[sys:c:save]");
filterMap.put("/exit","logout");
2.在shiroConfig.java中配置基于cookie的rememberMe管理器
@Bean
public CookieRememberMeManager cookieRememberMeManager(){
CookieRememberMeManager rememberMeManager = new CookieRememberMeManager();
SimpleCookie cookie = new SimpleCookie("rememberMe");
cookie.setMaxAge(30*24*60*60);
rememberMeManager.setCookie(cookie);
return rememberMeManager;
}
@Bean
public DefaultWebSecurityManager getDefaultWebSecurityManager(MyRealm myRealm){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(myRealm);
securityManager.setCacheManager(getEhCacheManager());
securityManager.setSessionManager(getDefaultWebSessionManager());
securityManager.setRememberMeManager(cookieRememberMeManager());
return securityManager;
}
3.登录认证时设置token"记住我"
@Service
public class UserServiceImpl {
public void checkLogin(String userName,String userPwd,Boolean rememberMe) throws Exception{
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(userName, userPwd);
token.setRememberMe(rememberMe);
subject.login(token);
}
}