Shiro(3)——授权

授权,也就是访问控制,即在应用中控制谁能访问哪些资源,比如页面访问、数据编辑等等操作的权限。在授权操作中需要这样几个关键对象:主体(Subject)、资源(Resources)、权限(Permission)、角色(Role)。

主体

主体也就是当前的用户,在Shiro中使用Subject代表当前用户。该用户只有被授权之后才能访问相应的资源

资源

应用中的图片、打印、页面、一些业务方法等等一切可以被访问的东西都可以称为资源。资源只能被具备权限的用户所访问。

权限

安全策略中的原子单位,通过权限决定用户能否访问应用中的某些资源。Shiro支持粒度权限,所谓粒度,就是指权限的范围大小,例如粗粒度:用户的所有权限,细粒度:访问某一个单个资源的权限。

角色

代表了权限的集合,一般赋予用户角色而不是权限,这样在授予权限的时候,我们可以向用户一次性授予一组权限,方便实际开发。例如:技术总监、产品经理、客户经理等等角色可以拥有不同组别的权限。
确切地说,shiro支持两种角色模式:

  1. 传统角色:一个角色代表着一系列的操作,当需要对某一操作进行授权验证时,只需要判断是否是指定角色即可。这种角色权限简单、模糊,不利于扩展。
  2. 权限角色:一个角色拥有一个权限的集合,授权验证时判断该角色是否拥有该权限即可。这种角色模式能够对角色进行详尽的权限描述,适合复杂的权限设计。

授权方式

Shiro有三种形式的授权方式。

1.编程式

1.1 传统角色授权实现
Subject currUser=SubjectUtils.getSubject();
if(currUser.hasRole("admin")){
    //拥有该权限
}else{
    //验证失败,没有权限
}

Subject实例的方法:

 //当用户具有指定角色时返回true
 boolean hasRole(String roleName);
 //判定用户是否具有指定列表中角色,按照顺序返回boolean数组
 boolean[] hasRoles(List<String> roleNames);
 //用户具有指定所有角色时返回true
 boolean hasAllRoles(Collection<String> roleNames);

上述属于传统角色模式。Shiro支持断言式的授权验证,当验证成功时并不返回任何值,程序正常执行,失败则抛出异常。Subject的断言验证的方法:

    void checkRole(String var1) throws AuthorizationException;

    void checkRoles(Collection<String> var1) throws AuthorizationException;

    void checkRoles(String... var1) throws AuthorizationException;
1.2 基于权限角色授权实现

相比传统授权模式,权限角色的方式耦合性会更低,它不会因为角色的变更而需要对源码进行修改,因此,权限角色模式是更好的访问控制方式。它的编程实现有下列方式:

1.2.1基于权限对象的实现
创建org.apache.shiro.authz.Permisson的实例,它是一个接口,并将该实例对象作为参数传递给Subject对象的isPerimitted()方法,如下:

Permission myPermission=new MyPermission();
Subject currUser=SubjectUtils.getSubject();
if(currUser.isPermitted(myPermission)){
    //do something
}else{
    //don't show API for currUser
}

Subject相关方法如下:

boolean isPermitted(Permission var1);
boolean[] isPermitted(List<Permission> var1);
boolean isPermittedAll(Collection<Permission> var1);

1.2.2 基于字符串的实现方式

Permission myPermission=new MyPermission();
Subject currUser=SubjectUtils.getSubject();
if(currUser.isPermitted("endSupport:admin:adminID")){
    //do something
}else{
    //don't show API for currUser
}
//这里":"分隔的权限表达式是org.apache.shiro.authz.permission.WildcardPermission默认支持的实现方式。这里分别了资源、操作、资源ID。

1.2.3 基于权限对象的断言实现
权限对象也支持断言实现,这里不做赘述。以下是断言实现的相关方法:

checkPermission(Permission perm);
checkPermission(String perm);
//是否拥有指定所有权限
checkPermissions(Collection<Permission> perms);
//同上
checkPermissions(String perms);

2.注解式

Shiro注解支持AspectJ、Spring、Google-Guice等,可根据应用进行不同的配置。
相关注解:

2.1 @RequiresAuthentication

用于注解在用户类/属性/方法上,用以表明当前用户是需要经过认证的用户。

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

表明当前用户需为“guest”用户。

2.3 @RequiresPermissions

该方法需要用户拥有指定的权限

@RequiresPermissions("resource:operation")
public void doSomething(){
    //the method is only invioked by a Subject instance which is permitted to do something
}
2.4 @RequiresRoles

在需要权限验证的方法上标注注解:

@RequiresRoles("admin")
public void dealWith(){
    //  doSomething
}
2.5 @RequiresUser

需要当前用户为认证用户,或者已记住用户

3.标签式
在jsp页面内嵌入shiro标签以实现页面级别的权限控制。
首先引入shiro的相关标签库

<%@ taglib prefix="shiro" uri="shiro.apache.org/tags" %>
3.1 guest

验证当前用户是否为访客,即未认证用户(包含未记住)。

<shiro:guest>
    这里的内容只有“guest”可见。
</shiro:guest>
3.2 user

验证当前用户是否为已认证或已记住的用户。

<shiro:user>
    这里的内容只有“user”可见。
</shiro:user>
3.3 authenticated和notAuthenticated

验证当前用户是否是已认证用户,不包括已记住用户,这是和user的区别。

<shiro:authenticated>
    这里的内容只有“authenticated”可见。
</shiro:authenticated>

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

<shiro:notAuthenticated>
    这里的内容只有“authenticated”可见。
</shiro:notAuthenticated>
3.4 principal

<shiro:principal/>显示当前用户信息,通常是账户登录信息。

3.5 hasRole

验证当前用户是否属于指定角色

<shiro:hasRole name="admin">
    <!--有权限,doSomething-->
<shiro:hasRole>
3.6 lacksRole

它的逻辑和hadRole相反,当用户不属于指定角色时生效

<shiro:lacksRole name="admin">
    <!--有权限,doSomething-->
<shiro:lacksRole>
3.7 hasAnyRole

当用户属于指定多个角色中的任何一个角色时生效

<shiro:hasAnyRole name="aaa,bbb,ccc">
    <!--有权限,doSomething-->
</shiro:hasAnyRole>
3.8 hasPermission

验证当前用户是否拥有指定权限

<shiro:hasPermission name="aaa:bbb">
    <!--有权限,doSomething-->
</shiro:hasPermission >
3.9 lacksPermission

逻辑与hasPermission相反

<shiro:lacksPermission name="aaa:bbb">
    <!--有权限,doSomething-->
</shiro:lacksPermission >

授权流程

这里写图片描述

  1. 在应用程序中调用Subject实例的授权验证方法,例如isPermitted()或者hasRoles()等等,subject将会委托给SubjectManager,再由SubjectManager委托给Authorizer;
  2. Authorizer是真正的授权者,如果我们调用isPermitted(“user:view”),它首先会通过PermissionResolver将字符串转化为相应的Permission实例;
  3. 在进行授权之前,会调用相应Realm获取Subject相应的角色/权限来匹配传入的角色/权限;
  4. Authorizer会判断Realm的角色/权限与传入的是否匹配,如果有多个Realm,则会委托给ModularRealmAuthorizer进行循环判断,如果匹配如isPermitted*/hasRoles会返回true,否则返回false,表示授权失败;

ModularRealmAuthorizer的授权流程

  1. 首先检查相应的Realm是否实现了Authorizer接口;
  2. 如果实现了该接口,则调用isPermitted*/hasRoles*相应方法进行匹配;
  3. 如果有一个Realm返回true则授权成功,返回true,否则返回false。

Realm授权流程

如果是Realm进行授权的话,应该要继承AuthorizingRealm,流程如下:
1. 如果调用hasRole*,则直接获取AuthorizationInfo.getRoles()与传入的角色进行比较即可/如果调用的是isPermitted(“user:view”)*,首先通过PermissionResolver将字符串转换成相应的Permission实例,默认使用WildCardPermissionResolver,即转换为通配符的WildCardPermission。
2. 通过AuthorizationInfo.getObjectPermissions()得到permission的集合

Authorizer、PermissionResolver以及RolePermissionResolver

Authorizer的职责是进行授权(访问控制),是Shiro授权核心的入口点,提供了相应的角色/权限判断接口。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值