设为首页 收藏本站
查看: 843|回复: 0

[经验分享] Apache Shiro 使用手册(三)Shiro 授权

[复制链接]

尚未签到

发表于 2015-8-2 08:02:22 | 显示全部楼层 |阅读模式
授权即访问控制,它将判断用户在应用程序中对资源是否拥有相应的访问权限。
如,判断一个用户有查看页面的权限,编辑数据的权限,拥有某一按钮的权限,以及是否拥有打印的权限等等。
一、授权的三要素
授权有着三个核心元素:权限、角色和用户。
权限
权限是Apache Shiro安全机制最核心的元素。它在应用程序中明确声明了被允许的行为和表现。一个格式良好好的权限声明可以清晰表达出用户对该资源拥有的权限。
大多数的资源会支持典型的CRUD操作(create,read,update,delete),但是任何操作建立在特定的资源上才是有意义的。因此,权限声明的根本思想就是建立在资源以及操作上。
而我们通过权限声明仅仅能了解这个权限可以在应用程序中做些什么,而不能确定谁拥有此权限。
于是,我们就需要在应用程序中对用户和权限建立关联。
通常的做法就是将权限分配给某个角色,然后将这个角色关联一个或多个用户。
权限声明及粒度
Shiro权限声明通常是使用以冒号分隔的表达式。就像前文所讲,一个权限表达式可以清晰的指定资源类型,允许的操作,可访问的数据。同时,Shiro权限表达式支持简单的通配符,可以更加灵活的进行权限设置。
下面以实例来说明权限表达式。
可查询用户数据
User:view
可查询或编辑用户数据
User:view,edit
可对用户数据进行所有操作
User:* 或 user
可编辑id为123的用户数据
User:edit:123
角色
Shiro支持两种角色模式:
1、传统角色:一个角色代表着一系列的操作,当需要对某一操作进行授权验证时,只需判断是否是该角色即可。这种角色权限相对简单、模糊,不利于扩展。
2、权限角色:一个角色拥有一个权限的集合。授权验证时,需要判断当前角色是否拥有该权限。这种角色权限可以对该角色进行详细的权限描述,适合更复杂的权限设计。
下面将详细描述对两种角色模式的授权实现。
二、授权实现
Shiro支持三种方式实现授权过程:

  • 编码实现
  • 注解实现
  • JSP Taglig实现
1、基于编码的授权实现
1.1基于传统角色授权实现
当需要验证用户是否拥有某个角色时,可以调用Subject 实例的hasRole*方法验证。



Java代码 DSC0000.png

  • Subject currentUser = SecurityUtils.getSubject();  
  • if (currentUser.hasRole("administrator")) {  
  •     //show the admin button  
  • } else {  
  •     //don't show the button?  Grey it out?  
  • }  

相关验证方法如下:
Subject方法描述
hasRole(String roleName)当用户拥有指定角色时,返回true
hasRoles(List roleNames)按照列表顺序返回相应的一个boolean值数组
hasAllRoles(Collection roleNames)如果用户拥有所有指定角色时,返回true

断言支持
Shiro还支持以断言的方式进行授权验证。断言成功,不返回任何值,程序继续执行;断言失败时,将抛出异常信息。使用断言,可以使我们的代码更加简洁。



Java代码

  • Subject currentUser = SecurityUtils.getSubject();  
  • //guarantee that the current user is a bank teller and  
  • //therefore allowed to open the account:  
  • currentUser.checkRole("bankTeller");  
  • openBankAccount();  

断言的相关方法:
Subject方法描述
checkRole(String roleName)断言用户是否拥有指定角色
checkRoles(Collection roleNames)断言用户是否拥有所有指定角色
checkRoles(String... roleNames)对上一方法的方法重载

1.2 基于权限角色授权实现
相比传统角色模式,基于权限的角色模式耦合性要更低些,它不会因角色的改变而对源代码进行修改,因此,基于权限的角色模式是更好的访问控制方式。
它的代码实现有以下几种实现方式:
1、基于权限对象的实现
创建org.apache.shiro.authz.Permission的实例,将该实例对象作为参数传递给Subject.isPermitted()进行验证。



Java代码

  • Permission printPermission = new PrinterPermission("laserjet4400n", "print");  
  • Subject currentUser = SecurityUtils.getSubject();  
  • if (currentUser.isPermitted(printPermission)) {  
  •     //show the Print button  
  • } else {  
  •     //don't show the button?  Grey it out?  
  • }  
  • Permission printPermission = new PrinterPermission("laserjet4400n", "print");  
  • Subject currentUser = SecurityUtils.getSubject();  
  • if (currentUser.isPermitted(printPermission)) {  
  •     //show the Print button  
  • } else {  
  •     //don't show the button?  Grey it out?  
  • }  

相关方法如下:
Subject方法描述
isPermitted(Permission p)Subject拥有制定权限时,返回treu
isPermitted(List perms)返回对应权限的boolean数组
isPermittedAll(Collection perms)Subject拥有所有制定权限时,返回true

2、 基于字符串的实现
相比笨重的基于对象的实现方式,基于字符串的实现便显得更加简洁。



Java代码

  • Subject currentUser = SecurityUtils.getSubject();  
  • if (currentUser.isPermitted("printer:print:laserjet4400n")) {  
  •     //show the Print button  
  • } else {  
  •     //don't show the button?  Grey it out?  
  • }  

使用冒号分隔的权限表达式是org.apache.shiro.authz.permission.WildcardPermission 默认支持的实现方式。
这里分别代表了 资源类型:操作:资源ID
类似基于对象的实现相关方法,基于字符串的实现相关方法:
isPermitted(String perm)、isPermitted(String... perms)、isPermittedAll(String... perms)
基于权限对象的断言实现



Java代码

  • Subject currentUser = SecurityUtils.getSubject();  
  • //guarantee that the current user is permitted  
  • //to open a bank account:  
  • Permission p = new AccountPermission("open");  
  • currentUser.checkPermission(p);  
  • openBankAccount();  

基于字符串的断言实现



Java代码

  • Subject currentUser = SecurityUtils.getSubject();  
  • //guarantee that the current user is permitted  
  • //to open a bank account:  
  • currentUser.checkPermission("account:open");  
  • openBankAccount();  

断言实现的相关方法
Subject方法说明
checkPermission(Permission p)断言用户是否拥有制定权限
checkPermission(String perm)断言用户是否拥有制定权限
checkPermissions(Collection perms)断言用户是否拥有所有指定权限
checkPermissions(String... perms)断言用户是否拥有所有指定权限

2、基于注解的授权实现
Shiro注解支持AspectJ、Spring、Google-Guice等,可根据应用进行不同的配置。
相关的注解:
@ RequiresAuthentication
可以用户类/属性/方法,用于表明当前用户需是经过认证的用户。



Java代码

  • @RequiresAuthentication  
  • public void updateAccount(Account userAccount) {  
  •     //this method will only be invoked by a   
  •     //Subject that is guaranteed authenticated  
  •     ...  
  • }  

@ RequiresGuest
表明该用户需为”guest”用户
@ RequiresPermissions
当前用户需拥有制定权限



Java代码

  • @RequiresPermissions("account:create")  
  • public void createAccount(Account account) {  
  •     //this method will only be invoked by a Subject  
  •     //that is permitted to create an account  
  •     ...  
  • }  

@RequiresRoles
当前用户需拥有制定角色
@ RequiresUser
当前用户需为已认证用户或已记住用户
3、基于JSP  TAG的授权实现
Shiro提供了一套JSP标签库来实现页面级的授权控制。
在使用Shiro标签库前,首先需要在JSP引入shiro标签:



Java代码

  •   

下面一一介绍Shiro的标签:
guest标签
验证当前用户是否为“访客”,即未认证(包含未记住)的用户



Xml代码

  •   
  •     Hi there!  Please Login or Signup today!  
  •   

user标签
认证通过或已记住的用户



Xml代码

  •   
  •     Welcome back John!  Not John? Click here to login.  
  •   

authenticated标签
已认证通过的用户。不包含已记住的用户,这是与user标签的区别所在。



Xml代码

  •   
  •     Update your contact information.  
  •   

notAuthenticated标签
未认证通过用户,与authenticated标签相对应。与guest标签的区别是,该标签包含已记住用户。



Xml代码

  •   
  •     Please login in order to update your credit card information.  
  •   

principal 标签
输出当前用户信息,通常为登录帐号信息



Xml代码

  • Hello, , how are you today?  

hasRole标签
验证当前用户是否属于该角色



Xml代码

  •   
  •     Administer the system  
  •   

lacksRole标签
与hasRole标签逻辑相反,当用户不属于该角色时验证通过



Xml代码

  •   
  •     Sorry, you are not allowed to administer the system.  
  •   

hasAnyRole标签
验证当前用户是否属于以下任意一个角色。



Xml代码

  •   
  •     You are either a developer, project manager, or administrator.  
  •   

hasPermission标签
验证当前用户是否拥有制定权限



Xml代码

  •   
  •     Create a new User  
  •   

lacksPermission标签
与hasPermission标签逻辑相反,当前用户没有制定权限时,验证通过



Xml代码

  •   
  •     Create a new User  
  •   

三、Shiro授权的内部处理机制
DSC0001.png
1、在应用程序中调用授权验证方法(Subject的isPermitted*或hasRole*等)
2、Sbuject的实例通常是DelegatingSubject类(或子类)的实例对象,在认证开始时,会委托应用程序设置的securityManager实例调用相应的isPermitted*或hasRole*方法。
3、接下来SecurityManager会委托内置的Authorizer的实例(默认是ModularRealmAuthorizer 类的实例,类似认证实例,它同样支持一个或多个Realm实例认证)调用相应的授权方法。
4、每一个Realm将检查是否实现了相同的 Authorizer 接口。然后,将调用Reaml自己的相应的授权验证方法。
当使用多个Realm时,不同于认证策略处理方式,授权处理过程中:
1、当调用Realm出现异常时,将立即抛出异常,结束授权验证。
2、只要有一个Realm验证成功,那么将认为授权成功,立即返回,结束认证。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-93146-1-1.html 上篇帖子: 修改apache默认路径 下篇帖子: Caused by: java.lang.ClassNotFoundException:org.apache.commons.logging.LogFactor
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表