1、过滤器授权
1、在realm中查询用户的权限和角色放到缓存中
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
//第一步:先获取用户名
User user= (User) principalCollection.getPrimaryPrincipal();
//第二步:通过用户名查询数据库 当前用户具有的权限 以及角色
// ....
// ...
Set<String> perms=new HashSet<>();
perms.add("ad:add");
Set<String> roles=new HashSet<>();
roles.add("seller");
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo(roles);
simpleAuthorizationInfo.setStringPermissions(perms);
return simpleAuthorizationInfo;
}
2、在HTML页面上设置访问元素
<a href="/addUser">添加用户</a>
3、在配置文件中配置过滤器授权
maps.put("/addUser","perms[user:add]"); //要请求这个地址 用户必
4.5.2、注解授权
简单的、它要写个注解就可以了
1、在配置文件中配置aop对注解的支持
//下面配置AOP对注解的支持(也就是shiro中注解的支持)
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(
@Qualifier("securityManager") DefaultWebSecurityManager securityManager){
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
}
@Bean
@ConditionalOnMissingBean
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator(){
DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
return defaultAdvisorAutoProxyCreator;
}
2、在方法上使用注解来完成权限的判断
@RequestMapping("toDelete")
@RequiresPermissions({"user:delete"}) //要访问当前的方法必须具有user:delete的权限才能访问
//@RequiresRoles({"seller"})
public String toDelete(){
return "delete";
}
4.5.3、HTML页面上基于Thymeleaf的支持
1、导包
<!--导入thymeleaf对shiro的支持包-->
<dependency>
<groupId>com.github.theborakompanioni</groupId>
<artifactId>thymeleaf-extras-shiro</artifactId>
<version>2.0.0</version>
</dependency>
2、配置方言
/*配置shiro-dialect这个方言*/
@Bean
public ShiroDialect shiroDialect(){
return new ShiroDialect();
}
3、使用shiro的标签
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org"
xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
欢迎<span th:text="${user.userName}"></span>大爷再次回来.....
this is index Page And you? <br>
<a href="/logout">退出</a><br>
<hr>
<a href="/addUser">添加用户(测试过滤器授权)</a>
<br>
<a href="/toDelete">用户删除(测试注解授权)</a>
<!--下面玩下shiro标签库中的标签-->
<!--<shiro:authenticated>
<span>
用户的身份验证是成功的
</span>
</shiro:authenticated>
<shiro:guest>
<span>你是游客</span>
</shiro:guest>
<shiro:hasPermission name="user:add">
<span>用户必须具有某一个权限才能访问</span>
</shiro:hasPermission>
<shiro:hasAllRoles name="buyer,seller">
<span>拥有某一个角色下面才显示</span>
</shiro:hasAllRoles>
<shiro:lacksPermission>
<span>没有某一个权限的时候才能访问</span>
</shiro:lacksPermission>
<shiro:lacksRole name="xxx">
<span>没有某一个角色的时候才能访问</span>
</shiro:lacksRole>
<shiro:notAuthenticated>
<span>没有认证通过才能显示</span>
</shiro:notAuthenticated>
-->
<hr>
<!--下面就是显示用户信息的-->
<shiro:principal property="userName"/> <br>
<!--下面这个标签就表示的是用户已经登陆-->
<shiro:user>
<label>欢迎[<shiro:principal property="userName"/>]登陆</label>
</shiro:user>
</body>
</html>
4.6、缓存的使用
明白一个问题、为什么要使用缓存
演示了每一次 授权的时候 都会去访问咋们的 realm中的授权的方法
这样的话咋们的数据库的压力就会比较大 这种情况下 咋们缓存就应运而生了
缓存是缓存的是咋们的的这个授权信息的(不是其他信息)
4.6.1、导包
<!--下面就是缓存需要的包-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>2.10.4</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>1.4.0</version>
</dependency>
4.6.2、在resources下创建ehcache.xml配置文件
<?xml version="1.0" encoding="UTF-8"?>
<ehcache updateCheck="false" dynamicConfig="false">
<diskStore path="G:\mytemp" />
<cache name="users"
timeToLiveSeconds="300"
maxEntriesLocalHeap="1000"/>
<!--
name:缓存名称。
maxElementsInMemory:缓存最大个数。
eternal:对象是否永久有效,一但设置了,timeout将不起作用。
timeToIdleSeconds:设置对象在失效前的允许闲置时间(单位:秒)。仅当eternal=false对象不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大。
timeToLiveSeconds:设置对象在失效前允许存活时间(单位:秒)。最大时间介于创建时间和失效时间之间。仅当eternal=false对象不是永久有效时使用,默认是0.,也就是对象存活时间无穷大。
overflowToDisk:当内存中对象数量达到maxElementsInMemory时,Ehcache将会对象写到磁盘中。
diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。
maxElementsOnDisk:硬盘最大缓存个数。
diskPersistent:是否缓存虚拟机重启期数据 Whether the disk store persists between restarts of the Virtual Machine. The default value is false.
diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。
memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。
clearOnFlush:内存数量最大时是否清除。
-->
<defaultCache name="defaultCache"
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="false"
maxElementsOnDisk="100000"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU"/>
</ehcache>
4.6.3、在ShiroConfig中进行缓存的配置
//下面进行缓存的配置
@Bean
public EhCacheManager ehCacheManager(){
EhCacheManager ehCacheManager = new EhCacheManager();
ehCacheManager.setCacheManagerConfigFile("classpath:ehcache.xml");
return ehCacheManager;
}
4.6.4、在安全管理器上面进行配置
//配置的是安全管理器
@Bean
public DefaultWebSecurityManager securityManager(@Qualifier("myRealm") MyRealm myRealm){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
//设置校验的realm对象
logger.info("securityManager的过滤器执行了.....");
securityManager.setRealm(myRealm);
//下面就设置缓存了
securityManager.setCacheManager(ehCacheManager());
return securityManager;
}
4.7、session的管理
4.7.1、在ShiroConfig中进行配置
//Session的管理
public DefaultWebSessionManager sessionManager(){
DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
//Session到底的时候是否自动删除
sessionManager.setDeleteInvalidSessions(true);
//设置session的超时时间
sessionManager.setGlobalSessionTimeout(1);
return sessionManager;
}
4.7.2、在SecurityManager
@Bean
public DefaultWebSecurityManager securityManager(@Qualifier("myRealm") MyRealm myRealm){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
//设置校验的realm对象
logger.info("securityManager的过滤器执行了.....");
securityManager.setRealm(myRealm);
//下面就设置缓存了
securityManager.setCacheManager(ehCacheManager());
//设置Session的管理
securityManager.setSessionManager(sessionManager());
return securityManager;
}
4.8、rememeberMe功能的实现
Session+Cookie的模式来做 记住我这个功能
4.8.1、配置ShiroConfig
//下面做的就是rememeberMe的这个功能
@Bean
public CookieRememberMeManager rememberMeManager(){
CookieRememberMeManager rememberMeManager = new CookieRememberMeManager();
//设置咋们的Cookie
rememberMeManager.setCookie(simpleCookie());
return rememberMeManager;
}
/**
* 自定义一个Cookie对象
* @return
*/
@Bean
public SimpleCookie simpleCookie(){
SimpleCookie simpleCookie = new SimpleCookie("rememebenrMe");
simpleCookie.setMaxAge(2592000);
return simpleCookie;
}
4.8.2、在HTML页面上添加记住我的这个功能
<form action="/login" method="post">
用户名:<input type="text" name="userName"/><span th:text="${userNameError}"></span><br>
密码:<input type="password" name="password"><span th:text="${passwordError}"></span><br>
是否使用记住我的这个功能:<input type="checkbox" name="rememberMe"><br>
<input type="submit" value="登陆">
</form>
4.8.3、在认证的token上设置记住我的这个方法
@RequestMapping(value = "login")
public String login(User user, Model model,boolean rememberMe){
logger.info("接受到前端的数据rememebenrMe="+rememberMe);
//封装成请求对象
UsernamePasswordToken token = new UsernamePasswordToken(user.getUserName(), user.getPassword());
//设置记住我的这个功能
token.setRememberMe(rememberMe);
//获取登陆的主体对象
Subject subject = SecurityUtils.getSubject();
//登陆
try{
subject.login(token);
}catch (UnknownAccountException err){ //用户名不对
logger.error("用户名不对");
model.addAttribute("userNameError","用户名不对");
return "login";
}catch (IncorrectCredentialsException err){ //说明是密码不对
logger.error("密码不对");
model.addAttribute("passwordError","密码不对");
return "login";
}catch (Exception err){
logger.error("其他问题造成登陆失败:"+err.fillInStackTrace());
model.addAttribute("otherError","其他问题造成登陆失败");
return "login";
}
//首页要显示用户信息
//获取用户信息
//这个方法返回的数据 实际上就是 realm中认证的SimpleAuthticationInfo的第一个参数的数据
User user1= (User) SecurityUtils.getSubject().getPrincipal();
model.addAttribute("user",user);
return "index";
}
4.8.4、在过滤器中配置哪些页面使用了rememberme这个公共之后可以直接访问
public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("securityManager")DefaultWebSecurityManager securityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
logger.info("shiro的过滤器执行了.....");
//配置如果认证没有通过的话 那么跳转的这个页面
shiroFilterFactoryBean.setLoginUrl("/toLogin");
//如果没有 权限访问 那么就跳转到一个友好的也好的页面去提示用户
shiroFilterFactoryBean.setUnauthorizedUrl("/toUnAuthziration");
Map<String,String> maps=new LinkedHashMap<>();
//第一个参数是路劲 第二个参数是过滤器的名字
/**
* 常见的过滤器的名字以及含义
* /**:当前以及目录和后面的所有子目录全部都匹配上
* 127.0.0.1:8080/bobo 127.0.0.1:8080/bobo/xiaobobo
* /* :这个相当于只是匹配当前这一级的节点 127.0.0.1:8080/bobo
* 127.0.0.1:8080/bobo/xiaobobo
* authc:认证的过滤器
* anon: 表示的是/toIndex这个请求 不认证就可以访问 (匿名访问)
* maps.put("/toIndex","anon");
* logout:登陆过滤器
* maps.put("/logout","logout")
* perms:权限控制的
* roles:具有某一个角色才能访问
*
* 注意事项: /** 这个配置一定是最后 一个
*
*/
//maps.put("/toIndex","anon"); //表示的是不需要认证就可以访问
maps.put("/login","anon"); //访问请求的地址
maps.put("/logout","logout"); //这个就是退出功能
//设置哪些鞋面是使用了 rememeberMe功能之后 可以直接访问 不用认证了
maps.put("/addUser","user"); //这个设置的意思:假设我们使用了rememberMe这个功能那么 /addUser这个页面 就可以直接访问不需要认证了
maps.put("/toIndex","user"); //这个设置的意思:假设我们使用了rememberMe这个功能那么 /addUser这个页面 就可以直接访问不需要认证了
maps.put("/toDeleteUser","user"); //这个设置的意思:假设我们使用了rememberMe这个功能那么 /addUser这个页面 就可以直接访问不需要认证了
maps.put("/addUser","perms[user:add]"); //要请求这个地址 用户必须具有 user:add的权限
maps.put("/add","roles[seller]"); //要请求这个地址 用户必须具有 user:add的权限
maps.put("/**","authc"); //所有的请求都必须在用户认证之后才能访问 shiroFilterFactoryBean.setFilterChainDefinitionMap(maps);
//设置这个安全管理器
shiroFilterFactoryBean.setSecurityManager(securityManager);
return shiroFilterFactoryBean;
}