一、Authorizer、PermissionResolver及RolePermissionResolver

Authorizer的职责是进行授权(访问控制),是Shiro API中授权核心的入口点,其提供了相应的角色/权限判断接口,具体请参考其Javadoc。SecurityManager继承了Authorizer接口,且提供了ModularRealmAuthorizer用于多Realm时的授权匹配。PermissionResolver用于解析权限字符串到Permission实例,而RolePermissionResolver用于根据角色解析相应的权限集合。

二、案例

  • shiro.ini
[main]
#自定义authorizer
authorizer=org.apache.shiro.authz.ModularRealmAuthorizer
#自定义permissionResolver
#permissionResolver=org.apache.shiro.authz.permission.WildcardPermissionResolver
permissionResolver=servlet.BitAndWildPermissionResolver
authorizer.permissionResolver=$permissionResolver
#自定义rolePermissionResolver
rolePermissionResolver=servlet.MyRolePermissionResolver
authorizer.rolePermissionResolver=$rolePermissionResolver securityManager.authorizer=$authorizer #自定义realm 一定要放在securityManager.authorizer赋值之后(因为调用setRealms会将realms设置给authorizer,并给各个Realm设置permissionResolver和rolePermissionResolver)
realm=realms.MyRealm1
securityManager.realms=$realm
  • 对于ModularRealmAuthorizer,相应的AuthorizingSecurityManager会在初始化完成后自动将相应的realm设置进去,我们也可以通过调用其setRealms()方法进行设置
  • BitPermission.java
package servlet;

import org.apache.shiro.authz.Permission;

/**
* BitPermission用于实现位移方式的权限,如规则是:
*
* 权限字符串格式:+资源字符串+权限位+实例ID;以+开头中间通过+分割;权限:0 表示所有权限;1 新增(二进制:0001)、2
* 修改(二进制:0010)、4 删除(二进制:0100)、8 查看(二进制:1000);如 +user+10 表示对资源user拥有修改/查看权限。
*
* @author Administrator
*
*/
public class BitPermission implements Permission {
private String resourceIdentify;
private int permissionBit;
private String instanceId; public BitPermission(String permissionString) {
String[] array = permissionString.split("\\+");
if (array.length > 1) {
resourceIdentify = array[1];
}
if (resourceIdentify == null || resourceIdentify.equals("")) {
resourceIdentify = "*";
}
if (array.length > 2) {
permissionBit = Integer.valueOf(array[2]);
}
if (array.length > 3) {
instanceId = array[3];
}
if (instanceId == null || resourceIdentify.equals("")) {
instanceId = "*";
}
} public boolean implies(Permission p) {
if (!(p instanceof BitPermission)) {
return false;
}
BitPermission other = (BitPermission) p;
if (!("*".equals(this.resourceIdentify) || this.resourceIdentify.equals(other.resourceIdentify))) {
return false;
}
if (!(this.permissionBit == 0 || (this.permissionBit & other.permissionBit) != 0)) {
return false;
}
if (!("*".equals(this.instanceId) || this.instanceId.equals(other.instanceId))) {
return false;
}
return true;
}
}
  • BitPermission用于实现位移方式的权限,如规则是:

    权限字符串格式:+资源字符串+权限位+实例ID;以+开头中间通过+分割;权限:0 表示所有权限;1 新增(二进制:0001)、2 修改(二进制:0010)、4 删除(二进制:0100)、8 查看(二进制:1000);如 +user+10 表示对资源user拥有修改/查看权限。

  • Permission接口提供了boolean implies(Permission p)方法用于判断权限匹配的.
  • MyRolePermissionResolver.java:RolePermissionResolver用于根据角色字符串来解析得到权限集合
    public class MyRolePermissionResolver implements RolePermissionResolver {
    public Collection<Permission> resolvePermissionsInRole(String roleString) {
    if("role1".equals(roleString)) {
    return Arrays.asList((Permission)new WildcardPermission("menu:*"));
    }
    return null;
    }
    }
     
  • 自定义Realm.java
public class MyRealm1 extends AuthorizingRealm{

    /**
* 判断授权的
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
authorizationInfo.addRole("role1");
authorizationInfo.addRole("role2");
authorizationInfo.addObjectPermission(new BitPermission("+user1+10"));
authorizationInfo.addObjectPermission(new WildcardPermission("user1:*"));
authorizationInfo.addStringPermission("+user2+10");
authorizationInfo.addStringPermission("user2:*");
return authorizationInfo;
} /**
* 判断认证的
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
String userName=token.getPrincipal().toString();
String passWord=new String((char[])token.getCredentials()); if(!userName.equals("zhang")) throw new UnknownAccountException("Realm1 用户名错误");
if(!passWord.equals("123")) throw new IncorrectCredentialsException("Realm1 密码错误"); return new SimpleAccount(userName, passWord, getName());
} }
  • 此次还要注意就是不能把我们自定义的如“+user1+10”配置到INI配置文件,即使有IniRealm完成,因为IniRealm在new完成后就会解析这些权限字符串,默认使用了WildcardPermissionResolver完成,即此处是一个设计权限,如果采用生命周期(如使用初始化方法)的方式进行加载就可以解决我们自定义permissionResolver的问题。
public class TestMain {
public static void main(String[] args) {
SecurityManager securityManager=new IniSecurityManagerFactory("classpath:shiro.ini").getInstance();
SecurityUtils.setSecurityManager(securityManager); Subject subject=SecurityUtils.getSubject();
subject.login(new UsernamePasswordToken("zhang", "123")); //通过二进制位的方式表示权限
System.out.println(subject.isPermitted("+user1+2"));//新增权限
System.out.println(subject.isPermitted("+user1+8"));//查看权限
System.out.println(subject.isPermitted("+user2+10"));//新增及查看 System.out.println(subject.isPermitted("+user1+4"));//没有删除权限
System.out.println(subject.isPermitted("menu:view"));//通过MyRolePermissionResolver解析得到的权限
}
}

  • 流程如下:

1、首先调用Subject.isPermitted*/hasRole*接口,其会委托给SecurityManager,而SecurityManager接着会委托给Authorizer;

2、Authorizer是真正的授权者,如果我们调用如isPermitted(“user:view”),其首先会通过PermissionResolver把字符串转换成相应的Permission实例;

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

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

 本例中的流程大概是:

1.System.out.println(subject.isPermitted("+user1+2"));
2.BitAndWildPermissionResolver把字符串转换成相应的Permission实例(调用BitPermission的构造方法,参数为"+user1+2",解析该参数并封装到BitPermission的成员变量中,即将该参数转为BitPermission实例)
3.MyRealm1中的doGetAuthorizationInfo方法获取Subject相应的角色/权限用于匹配传入的角色/权限

(六)授权(下):自定义permission的更多相关文章

  1. ASP.NET Core MVC 2.x 全面教程_ASP.NET Core MVC 18. 基于Claim和Policy的授权 下 - 自定义Policy

    在加一个策略,要求cliam的值必须是123 第二个参数的类型 可变参数 ,可以是这三种类型 变成一个集合也可以 策略内置的几种方式 自定义 RequireAssetion的参数是个Func,Func ...

  2. Asp.net Core 系列之--5.认证、授权与自定义权限的实现

    ChuanGoing 2019-11-24 asp.net core系列已经来到了第五篇,通过之前的基础介绍,我们了解了事件订阅/发布的eventbus整个流程,初探dapper ORM实现,并且简单 ...

  3. Android 自定义 permission

    Android 自定义 permission Android 添加自定义权限 permission-tree 权限的根节点,3个成员都要定义 name 一般来说需要2个".":比如 ...

  4. spring security 授权方式(自定义)及源码跟踪

    spring security 授权方式(自定义)及源码跟踪 ​ 这节我们来看看spring security的几种授权方式,及简要的源码跟踪.在初步接触spring security时,为了实现它的 ...

  5. 在String()构造器不存在的情况下自定义一个MyString()函数,实现如下内建String()方法和属性:

    在String()构造器不存在的情况下自定义一个MyString()函数,实现如下内建String()方法和属性: var s = new MyString("hello"); s ...

  6. vs 2013下自定义ASP.net MVC 5/Web API 2 模板(T4 视图模板/控制器模板)

    vs 2013下自定义ASP.net MVC 5/Web API 2  模板(T4 视图模板/控制器模板): Customizing ASP.NET MVC 5/Web API 2 Scaffoldi ...

  7. 第四百零六节,自定义用户表类来继承Django的用户表类,

    第四百零六节,自定义用户表类来继承Django的用户表类, models.py from django.db import models # Create your models here. from ...

  8. VS2012下自定义打开文件对话框

    VS2012下自定义打开文件对话框,MFC的CFileDialog封装了太多,太复杂,绕得头晕,自己封装一个得了 #pragma once #include <objbase.h> #in ...

  9. SpringCloud微服务实战——搭建企业级开发框架(二十六):自定义扩展OAuth2实现短信验证码登录

    现在手机验证码登录似乎是每个网站必备的功能,OAuth2支持扩展自定义授权模式,前面介绍了如何在系统集成短信通知服务,这里我们进行OAuth2的授权模式自定义扩展,使系统支持短信验证码登录. 1.在g ...

随机推荐

  1. JS 将页面上的表格导出为 Excel 文件

    如果在页面上展示了一个表格,想把这个表格导出为Excel文件,那么在要求不高的情况下,可以直接利用 JavaScript 的 Blob 和 Object URL 特性将表格导出.不过,这就是利用了 E ...

  2. 线程池 | Java多线程,彻底搞懂线程池

    熟悉Java多线程编程的同学都知道,当我们线程创建过多时,容易引发内存溢出,因此我们就有必要使用线程池的技术了. 最近看了一些相关文章,并亲自研究了一下源码,发现有些文章还是有些问题的,所以我也总结了 ...

  3. insmod某个内核模块时提示“Failed to find the folder holding the modules”如何处理?

    答: 创建/lib/modules/$(uname -r)目录,命令如下: mkdir /lib/modules/$(uname -r)

  4. [Java复习] 分布式事务 Part 1

    1. CAP理论 C: Consistency 一致性 A: Availability 可用性 P: Partition tolerance 分区容错性 CAP定理:一个分布式系统不可能同时满足CAP ...

  5. HTTP中的请求头和响应头属性解析

    HTTP中的请求头和响应头属性解析 下面总结一下平时web开发中,HTTP请求的相关过程以及重要的参数意义 一次完整的HTTP请求所经历的7个步骤 说明:HTTP通信机制是在一次完整的HTTP通信过程 ...

  6. (二)UML之类图、接口、包

    一.概念 类图(Class Diagram): 类图是面向对象系统建模中最常用和最重要的图,是定义其它图的基础.类图主要是用来显示系统中的类.接口以及它们之间的静态结构和关系的一种静态模型. 类图的3 ...

  7. laravel门面DB返回数组配置

    在数据库配置文件中添加 'fetch' => PDO::FETCH_ASSOC, //但是这个配置好像是全局的,不能针对单个数据库连接进行配置 也可以在方法内使用php内置函数get_objec ...

  8. DB2中的NVL和NVL2函数

    NVL函数是一个空值转换函数 NVL(表达式1,表达式2) 如果表达式1为空值,NVL返回值为表达式2的值,否则返回表达式1的值. 该函数的目的是把一个空值(null)转换成一个实际的值.其表达式的值 ...

  9. 它在 ServiceHost 指令中提供为 Service 特性值,或在配置元素 system.serviceModel/serviceHostingEnvironment/serviceActivations 中提供

    找不到类型“Services.CalculatorService”,它在 ServiceHost 指令中提供为 Service 特性值,或在配置元素 system.serviceModel/servi ...

  10. [CareerCup] Guards in a museum 博物馆的警卫

    A museum was represented by a square matrix that was filled with O, G, and W where O represented ope ...