Shiro中的授权问题
在初识Shiro一文中,我们对Shiro的基本使用已经做了简单的介绍,不懂的小伙伴们可以先阅读上文,今天我们就来看看Shiro中的授权问题。
Shiro中的授权,大体上可以分为两大类,一类是隐式角色,还有一类是显式角色。我们来分别看下。
隐式角色
隐式角色是一种基于角色的访问权限控制,它在使用的过程中,我们直接判断相应的Subject是否是某一种角色,进而判断该Subject是否具备某种权限,比如下面一个例子:
定义用户
在ini文件中定义用户和对应的角色:
[users]
zhang=123,role1,role2
wang=123,role1
两个用户,zhang用户具有role1、role2两种角色,wang用户具有role1一种角色。
判断用户是否具备某种角色
先来个方法用来执行登录操作,如下:
private void login(String iniFile, String username, String password) {
Factory<SecurityManager> factory = new IniSecurityManagerFactory(iniFile);
SecurityManager securityManager = factory.getInstance();
SecurityUtils.setSecurityManager(securityManager);
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
try {
subject.login(token);
System.out.println("登录成功");
} catch (AuthenticationException e) {
System.out.println("登录失败");
e.printStackTrace();
}
}
这个登录比较简单,我们在上文中有详细介绍。
OK,我们看看如何测试:
@Test
public void test1() {
login("classpath:shiro.ini", "zhang", "123");
Subject subject = SecurityUtils.getSubject();
//判断是否具备某一种权限
Assert.assertTrue(subject.hasRole("role1"));//OK
Assert.assertTrue(subject.hasRole("role2"));//OK
List<String> roles = new ArrayList<String>();
roles.add("role1");
roles.add("role2");
roles.add("role3");
//判断是否具备某一组权限
Assert.assertArrayEquals(new boolean[]{true, true, false}, subject.hasRoles(roles));//OK
}
OK,上文的测试结果都是OK的,我们用hasRole方法来判断某一个Subject是否具备某一种权限,用hasRoles方法来判断某一个Subject是否具备某一组权限。
可能有的小伙伴已经发现了这种方法的弊端,如果有一天我不需要这些判断了该怎么办?一个一个修改?太可怕了!so,我们来看看下文的显示角色是怎么一回事。
显式角色
显式角色是一种基于资源的访问权限控制,使用显式角色可以避免上文提到的问题,但是使用显式角色又需要我们自己手动维护用户-角色、角色-权限之间的关系。
OK ,我们先来看一个简单的案例。
单个资源具备多个权限
在ini文件中定义两个用户:
[users]
zhang = 123,role1,role2
wang = 123,role1
两个用户具备两种角色,然后再定义这两种角色对应的权限,权限的定义格式一般是资源:操作:
[roles]
#单个资源多个权限
role1 = user:create,user:update
role2 = user:create,user:delete
role1和role2分别具备两种不同的权限。
我们来看看测试
@Test
public void test2() {
login("classpath:shiro-res.ini", "wang", "123");
Subject subject = SecurityUtils.getSubject();
Assert.assertTrue(subject.isPermitted("user:create"));//OK
Assert.assertFalse(subject.isPermittedAll("user:delete", "user:update"));//OK
Assert.assertFalse(subject.isPermitted("user:view"));//OK
}
以上测试结果都是OK的,wang这个用户具备user:create权限,但是它不同时具备user:delete和user:update权限,同时它也不具有user:view权限。
OK,单个资源具备多个权限除了上面的定义方式之外,我们也可以按下面的方式来定义:
#单个资源的多个权限
role3 = system:user:update,system:user:delete
#role3可以简写为下面这种形式
role31 = "system:user:update,delete"
注意,第二种写法要加引号,这两种都是表示相应的角色具备update和delete权限。测试方法如下:
@Test
public void role3Test() {
login("classpath:shiro-res.ini", "user_role3", "123");
Subject subject = SecurityUtils.getSubject();
Assert.assertTrue(subject.isPermitted("system:user:update"));//OK
Assert.assertTrue(subject.isPermitted("system:user:delete"));//OK
}
@Test
public void role31Test() {
login("classpath:shiro-res.ini", "user_role31", "123");
Subject subject = SecurityUtils.getSubject();
Assert.assertTrue(subject.isPermitted("system:user:update"));//OK
Assert.assertTrue(subject.isPermitted("system:user:delete"));//OK
Assert.assertTrue(subject.isPermitted("system:user:update,delete"));//OK
}
这里的测试结果都是OK的。
单个资源具有全部权限
ini配置如下:
#单个资源全部权限
role4 = "system:user:update,create,delete,view"
#role4可以简写为下面的形式
role41 = system:user:*
#role4也可以简写为下面的形式
role42 = system:user
注意这种有两种不同的简写方式,一种是用*作为通配符,还有一种就是干脆省略。
我们来看看测试方式:
@Test
public void role4Test() {
login("classpath:shiro-res.ini", "user_role4", "123");
Subject subject = SecurityUtils.getSubject();
Assert.assertTrue(subject.isPermitted("system:user:update"));//OK
Assert.assertTrue(subject.isPermitted("system:user:delete"));//OK
Assert.assertTrue(subject.isPermitted("system:user:view"));//OK
Assert.assertTrue(subject.isPermitted("system:user:create"));//OK
Assert.assertTrue(subject.isPermitted("system:user:update,delete,view,create"));//OK
Assert.assertTrue(subject.isPermitted("system:user:update,delete,create"));//OK
}
@Test
public void role41Test() {
login("classpath:shiro-res.ini", "user_role41", "123");
Subject subject = SecurityUtils.getSubject();
Assert.assertTrue(subject.isPermitted("system:user:update"));//OK
Assert.assertTrue(subject.isPermitted("system:user:delete"));//OK
Assert.assertTrue(subject.isPermitted("system:user:view"));//OK
Assert.assertTrue(subject.isPermitted("system:user:create"));//OK
Assert.assertTrue(subject.isPermitted("system:user:update,delete,view,create"));//OK
Assert.assertTrue(subject.isPermitted("system:user:update,delete,create"));//OK
Assert.assertTrue(subject.isPermitted("system:user:*"));//OK
Assert.assertTrue(subject.isPermitted("system:user"));//OK
}
@Test
public void role42Test() {
login("classpath:shiro-res.ini", "user_role42", "123");
Subject subject = SecurityUtils.getSubject();
Assert.assertTrue(subject.isPermitted("system:user:update"));//OK
Assert.assertTrue(subject.isPermitted("system:user:delete"));//OK
Assert.assertTrue(subject.isPermitted("system:user:view"));//OK
Assert.assertTrue(subject.isPermitted("system:user:create"));//OK
Assert.assertTrue(subject.isPermitted("system:user:update,delete,view,create"));//OK
Assert.assertTrue(subject.isPermitted("system:user:update,delete,create"));//OK
Assert.assertTrue(subject.isPermitted("system:user:*"));//OK
Assert.assertTrue(subject.isPermitted("system:user"));//OK
}
OK,以上三个方法分别测试三个不同的权限定义方式,结果都是OK的。
所有资源具有全部权限
当然我们也可以定义所有资源具有全部权限,定义方式如下:
#所有资源的全部权限 user:view
role5 = *:view
#system:user:view
role51 = *:*:view
*:view可以用来表示像user:view这种权限的定义,*:*:view则可以用来表示像system:user:view这种权限定义,我们来看看两个对应的测试方法:
@Test
public void role5Test() {
login("classpath:shiro-res.ini", "user_role5", "123");
Subject subject = SecurityUtils.getSubject();
Assert.assertTrue(subject.isPermitted("user:view"));//OK
}
@Test
public void role51Test() {
login("classpath:shiro-res.ini", "user_role51", "123");
Subject subject = SecurityUtils.getSubject();
Assert.assertTrue(subject.isPermitted("system:user:view"));//OK
}
两个测试结果都是OK的。
实例级别的权限
我们的权限定义也可以具体到实例级别,如下:
#单个实例单个权限
#对user的1拥有view权限
role6 = user:view:1
#单个实例多个权限
role61 = "user:update,delete:1"
#单个实例的所有权限
role62 = user:*:1
#所有实例的单个权限
role63 = user:view:*
#所有实例的所有权限
role64 = user:*:*
测试代码如下:
@Test
public void role6Test() {
login("classpath:shiro-res.ini", "user_role6", "123");
Subject subject = SecurityUtils.getSubject();
Assert.assertTrue(subject.isPermitted("user:view:1"));//OK
}
@Test
public void role61Test() {
login("classpath:shiro-res.ini", "user_role61", "123");
Subject subject = SecurityUtils.getSubject();
Assert.assertTrue(subject.isPermitted("user:update:1"));//OK
Assert.assertTrue(subject.isPermitted("user:delete:1"));//OK
Assert.assertTrue(subject.isPermitted("user:update,delete:1"));//OK
}
@Test
public void role62Test() {
login("classpath:shiro-res.ini", "user_role62", "123");
Subject subject = SecurityUtils.getSubject();
Assert.assertTrue(subject.isPermitted("user:update:1"));//OK
Assert.assertTrue(subject.isPermitted("user:delete:1"));//OK
Assert.assertTrue(subject.isPermitted("user:view:1"));//OK
Assert.assertTrue(subject.isPermitted("user:create:1"));//OK
Assert.assertTrue(subject.isPermitted("user:create,view,update,delete:1"));//OK
Assert.assertTrue(subject.isPermitted("user:update,delete:1"));//OK
}
@Test
public void role63Test() {
login("classpath:shiro-res.ini", "user_role63", "123");
Subject subject = SecurityUtils.getSubject();
Assert.assertTrue(subject.isPermitted("user:view:1"));//OK
Assert.assertTrue(subject.isPermitted("user:view:2"));//OK
Assert.assertTrue(subject.isPermitted("user:view:3"));//OK
Assert.assertTrue(subject.isPermitted("user:view:4"));//OK
}
@Test
public void role64Test() {
login("classpath:shiro-res.ini", "user_role64", "123");
Subject subject = SecurityUtils.getSubject();
Assert.assertTrue(subject.isPermitted("user:view:1"));//OK
Assert.assertTrue(subject.isPermitted("user:update:2"));//OK
Assert.assertTrue(subject.isPermitted("user:create:3"));//OK
Assert.assertTrue(subject.isPermitted("user:delete:4"));//OK
}
测试结果都是OK的。
其他
OK,关于授权,我们这里还有两个问题,前文我们说的system:user等价于system:user:*,而对于system,它除了等价于system:*,也等价于system:*:*,所以,我们可以把system:user或者system理解成一种前缀匹配。同时,我们用user:*可以匹配user:update、user:delete等,而user:delete又可以匹配user:delete:1,因此我们可以这样理解:不加*,我们可以做前缀匹配,加*,我们则可以匹配所有。
OK,以上就是Shiro中简单的授权问题。
案例下载:
https://github.com/lenve/Shiro/tree/master/Shiro2
更多JavaWeb资料,请移步这里:
https://github.com/lenve/JavaEETest
参考资料:
张开涛大神的《跟我学Shiro》,原文连接http://jinnianshilongnian.iteye.com/blog/2018398
关注公众号【江南一点雨】,专注于 Spring Boot+微服务以及前后端分离等全栈技术,定期视频教程分享,关注后回复 Java ,领取松哥为你精心准备的 Java 干货!

Shiro中的授权问题的更多相关文章
- Shiro中的授权问题(二)
上篇博客(Shiro中的授权问题 )我们介绍了Shiro中最最基本的授权问题,以及常见的权限字符的匹配问题.但是这里边还有许多细节需要我们继续介绍,本节我们就来看看Shiro中授权的一些细节问题. 验 ...
- shiro中的授权
- shiro入门学习--授权(Authorization)|筑基初期
写在前面 经过前面的学习,我们了解了shiro中的认证流程,并且学会了如何通过自定义Realm实现应用程序的用户认证.在这篇文章当中,我们将学习shiro中的授权流程. 授权概述 这里的授权指的是授予 ...
- 项目一:第十四天 1.在realm中动态授权 2.Shiro整合ehcache 缓存realm中授权信息 3.动态展示菜单数据 4.Quartz定时任务调度框架—Spring整合javamail发送邮件 5.基于poi实现分区导出
1 Shiro整合ehCache缓存授权信息 当需要进行权限校验时候:四种方式url拦截.注解.页面标签.代码级别,当需要验证权限会调用realm中的授权方法 Shiro框架内部整合好缓存管理器, ...
- 从零到实现Shiro中Authorization和Authentication的缓存
本文大纲 一.简介 二.缓存的概念 三.自定义实现缓存机制 四.什么是Ehcache 五.Ehcache怎么用 六.Spring对缓存的支持 七.Spring+Ehcache实现 八.Spring+S ...
- shiro中CacheManager相关的类结构介绍,提供redis Cache实现
cacheManager主要用于对shiro中的session.realm中的认证信息.授权信息进行缓存. 1.类结构 2.接口及类介绍 CacheManager 提供根据名字获取cache的作用. ...
- 【shiro】(4)---Shiro认证、授权案例讲解
Shiro认证.授权案例讲解 一.认证 1. 认证流程 2.用户密码已经加密.加盐的用户认证 (1)测试类 // 用户登陆和退出,这里我自定了一个realm(开发肯定需要自定义realm获取 ...
- shiro源码篇 - shiro认证与授权,你值得拥有
前言 开心一刻 我和儿子有个共同的心愿,出国旅游.昨天儿子考试得了全班第一,我跟媳妇合计着带他出国见见世面,吃晚饭的时候,一家人开始了讨论这个.我:“儿子,你的心愿是什么?”,儿子:“吃汉堡包”,我: ...
- Shiro中Realm
6.1 Realm [2.5 Realm]及[3.5 Authorizer]部分都已经详细介绍过Realm了,接下来再来看一下一般真实环境下的Realm如何实现. 1.定义实体及关系 即用户-角色 ...
随机推荐
- Python封装:实现输出一个文件夹下所有各个文件的地址存为列表集合内——Jason niu
def getAllImages(folder): assert os.path.exists(folder) assert os.path.isdir(folder) imageList = os. ...
- Makefile自学
MakeFile的规则 如果这个工程没有编译过,那么我们的所有C文件都要编译并被链接. 如果这个工程的某几个C文件被修改,那么我们只编译被修改的C文件,并链接目标程序. 如果这个工程的头文件被改变了, ...
- BZOJ3592 : Architext
首先特判多边形面积$=0$的情况,此时内部没有点,答案只会在顶点处取到. 对于面积$>0$的情况,离线询问,将所有多边形合在一起得到平面图,然后求出对偶图,那么每条多边形边的两侧分别对应对偶图中 ...
- GDKOI2017滚粗记
Preface 比赛成绩非常烂,却腐败得非常爽,但是gmh大爷因为和我们腐败,变得更强. 比赛策略有点问题,拼命想正解而没了暴力分 数论题做得比较少,导致只会找规律.知识点需要补充,如AC自动机,启发 ...
- 关于height、offsetheight、clientheight、scrollheight、innerheight、outerheight的区别
二.也是平时经常用到的offsetheight 它返回的高度是内容高+padding+边框,但是注意哦,木有加margin哦,当然一般也木有啥需要把margin加进去的,以上代码为例,结果显示上图h2 ...
- 配置NFS固定端口
NFS启动时会随机启动多个端口并向RPC注册,为了设置安全组以及iptables规则,需要设置NFS固定端口.NFS服务需要开启 mountd,nfs,nlockmgr,portmapper,rquo ...
- python语法_模块_os_sys
os模块:提供对此操作系统进行操作的接口 os.getcwd() 获取python运行的工作目录. os.chdir(r'C:\USERs') 修改当前工作目录. os.curdir 返回当前目录 ( ...
- mysql查看编码格式以及修改编码格式
1.进入mysql,输入show variables like 'character%';查看当前字符集编码情况,显示如下: 其中,character_set_client为客户端编码方式: char ...
- 阿里面试题,深入理解Java类加载机制
类的生命周期 包括以下 7 个阶段: 加载(Loading) 验证(Verification) 准备(Preparation) 解析(Resolution) 初始化(Initialization) 使 ...
- [Swift]LeetCode94. 二叉树的中序遍历 | Binary Tree Inorder Traversal
Given a binary tree, return the inorder traversal of its nodes' values. Example: Input: [1,null,2,3] ...