一、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. httpPostedFile实现WEBAPI文件上传

    public void PostUpload() { var httpPostedFile = HttpContext.Current.Request.Files; foreach(string p ...

  2. g 定时任务

    Package cron implements a cron spec parser and job runner. cron - GoDochttps://godoc.org/github.com/ ...

  3. SpringBoot持久层技术

    一.Springboot整合mybatis maven中添加对数据库与mybatis的依赖 <dependencies> <dependency> <groupId> ...

  4. 微信小程序测试检查点

    1.权限测试 需要检查以下几种情况下微信用户访问的权限1)未授权微信登录小程序未授权时,一般使用一些业务功能的时候,都会弹出提醒:先授权再操作对应功能.或在提交数据到后台的时候,会提示补充相关身份信息 ...

  5. Pattern 和 Matcher

    作用:应用这个 Pattern 和 Matcher 可以完成字符串获取功能 使用: // 获取模式器对象 Pattern p = Pattern.compile("a*b") ; ...

  6. Django学习笔记009-django models进行数据库增删查改

    引入models的定义 from app.models import  myclass class  myclass(): aa =  models. CharField (max_length=No ...

  7. VBScript把json字符串解析成json对象的2个方法

    这篇文章主要介绍了VBScript把json字符串解析成json对象的2个方法,本文通过MSScriptControl.ScriptControl和jscript实现,需要的朋友可以参考下 asp/v ...

  8. rf笔记

    1.使用robot 用例绝对路径 可执行用例 2.robot --h 可以查看命令用法 3. 创建字典 *** Settings *** Library         Collections *** ...

  9. PAT 甲级1057 Stack (30 分)(不会,树状数组+二分)*****

    1057 Stack (30 分)   Stack is one of the most fundamental data structures, which is based on the prin ...

  10. PAT 甲级 1037 Magic Coupon (25 分) (较简单,贪心)

    1037 Magic Coupon (25 分)   The magic shop in Mars is offering some magic coupons. Each coupon has an ...