您的位置:首页 > 其它

Shiro(3)——授权

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

主体

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

资源

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

权限

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

角色

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

确切地说,shiro支持两种角色模式:

传统角色:一个角色代表着一系列的操作,当需要对某一操作进行授权验证时,只需要判断是否是指定角色即可。这种角色权限简单、模糊,不利于扩展。

权限角色:一个角色拥有一个权限的集合,授权验证时判断该角色是否拥有该权限即可。这种角色模式能够对角色进行详尽的权限描述,适合复杂的权限设计。

授权方式

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 >


授权流程



在应用程序中调用Subject实例的授权验证方法,例如isPermitted()或者hasRoles()等等,subject将会委托给SubjectManager,再由SubjectManager委托给Authorizer;

Authorizer是真正的授权者,如果我们调用isPermitted(“user:view”),它首先会通过PermissionResolver将字符串转化为相应的Permission实例;

在进行授权之前,会调用相应Realm获取Subject相应的角色/权限来匹配传入的角色/权限;

Authorizer会判断Realm的角色/权限与传入的是否匹配,如果有多个Realm,则会委托给ModularRealmAuthorizer进行循环判断,如果匹配如isPermitted*/hasRoles会返回true,否则返回false,表示授权失败;

ModularRealmAuthorizer的授权流程

首先检查相应的Realm是否实现了Authorizer接口;

如果实现了该接口,则调用isPermitted*/hasRoles*相应方法进行匹配;

如果有一个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授权核心的入口点,提供了相应的角色/权限判断接口。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  shiro