RoleController 权限控制

本文来自「利牧羊」的投稿,♪(・ω・)ノ

合约总览

WeIdentity 源码分析 | 狗哥解码(一)

在上一篇的合约分析中,我们分析了 WeIDContract 部分,该合约由于不依赖于其他模块,因此是我们分析整个合约的良好切入点。

WeIdentity 源码分析 | 狗哥解码

同样,除了WeIDContract外,我们可以从架构图中发现RoIeController同样是不依赖于其他模块,因此RoIeController将作为我们第二个分析的合约。

pragma solidity ^0.4.4; /*  *       Copyright© (2018-2019) WeBank Co., Ltd.  *  *       This file is part of weidentity-contract.  *  *       weidentity-contract is free software: you can redistribute it and/or modify  *       it under the terms of the GNU Lesser General Public License as published by  *       the Free Software Foundation, either version 3 of the License, or  *       (at your option) any later version.  *  *       weidentity-contract is distributed in the hope that it will be useful,  *       but WITHOUT ANY WARRANTY; without even the implied warranty of  *       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the  *       GNU Lesser General Public License for more details.  *  *       You should have received a copy of the GNU Lesser General Public License  *       along with weidentity-contract.  If not, see <https://www.gnu.org/licenses/>.  */  /**  * @title RoleController  *  This contract provides basic authentication control which defines who (address)  *  belongs to what specific role and has what specific permission.  */  contract RoleController {      /**      * The universal NO_PERMISSION error code.      */     uint constant public RETURN_CODE_FAILURE_NO_PERMISSION = 500000;      /**      * Role related Constants.      */     uint constant public ROLE_AUTHORITY_ISSUER = 100;     uint constant public ROLE_COMMITTEE = 101;     uint constant public ROLE_ADMIN = 102;      /**      * Operation related Constants.      */     uint constant public MODIFY_AUTHORITY_ISSUER = 200;     uint constant public MODIFY_COMMITTEE = 201;     uint constant public MODIFY_ADMIN = 202;     uint constant public MODIFY_KEY_CPT = 203;      mapping (address => bool) private authorityIssuerRoleBearer;     mapping (address => bool) private committeeMemberRoleBearer;     mapping (address => bool) private adminRoleBearer;      function RoleController() public {         authorityIssuerRoleBearer[msg.sender] = true;         adminRoleBearer[msg.sender] = true;         committeeMemberRoleBearer[msg.sender] = true;     }      /**      * Public common checkPermission logic.      */     function checkPermission(         address addr,         uint operation     )          public          constant          returns (bool)      {         if (operation == MODIFY_AUTHORITY_ISSUER) {             if (adminRoleBearer[addr] || committeeMemberRoleBearer[addr]) {                 return true;             }         }         if (operation == MODIFY_COMMITTEE) {             if (adminRoleBearer[addr]) {                 return true;             }         }         if (operation == MODIFY_ADMIN) {             if (adminRoleBearer[addr]) {                 return true;             }         }         if (operation == MODIFY_KEY_CPT) {             if (authorityIssuerRoleBearer[addr]) {                 return true;             }         }         return false;     }      /**      * Add Role.      */     function addRole(         address addr,         uint role     )          public      {         if (role == ROLE_AUTHORITY_ISSUER) {             if (checkPermission(tx.origin, MODIFY_AUTHORITY_ISSUER)) {                 authorityIssuerRoleBearer[addr] = true;             }         }         if (role == ROLE_COMMITTEE) {             if (checkPermission(tx.origin, MODIFY_COMMITTEE)) {                 committeeMemberRoleBearer[addr] = true;             }         }         if (role == ROLE_ADMIN) {             if (checkPermission(tx.origin, MODIFY_ADMIN)) {                 adminRoleBearer[addr] = true;             }         }     }      /**      * Remove Role.      */     function removeRole(         address addr,         uint role     )          public      {         if (role == ROLE_AUTHORITY_ISSUER) {             if (checkPermission(tx.origin, MODIFY_AUTHORITY_ISSUER)) {                 authorityIssuerRoleBearer[addr] = false;             }         }         if (role == ROLE_COMMITTEE) {             if (checkPermission(tx.origin, MODIFY_COMMITTEE)) {                 committeeMemberRoleBearer[addr] = false;             }         }         if (role == ROLE_ADMIN) {             if (checkPermission(tx.origin, MODIFY_ADMIN)) {                 adminRoleBearer[addr] = false;             }         }     }      /**      * Check Role.      */     function checkRole(         address addr,         uint role     )          public          constant          returns (bool)      {         if (role == ROLE_AUTHORITY_ISSUER) {             return authorityIssuerRoleBearer[addr];         }         if (role == ROLE_COMMITTEE) {             return committeeMemberRoleBearer[addr];         }         if (role == ROLE_ADMIN) {             return adminRoleBearer[addr];         }     } } 

此合约并不算太难理解,它主要就包含了四个功能,分别是:addRole、removeRole、checkPermission、checkRole。

而其中的Permission是由Role所决定的,具体权限划分看下图即可。

WeIdentity 源码分析 | 狗哥解码

了解完合约的大体内容后,我们就通过调试来具体分析下该合约内的各功能。

在Remix上调试与分析各功能

打开Remix,这里我们使用的依旧是在线版Remix编译器。

http://remix.ethereum.org/

1)创建合约

WeIdentity 源码分析 | 狗哥解码

2)将RoleController.sol源码copy过去

3)部署合约与调用

WeIdentity 源码分析 | 狗哥解码

部署完成之后,我们就可以开始对各功能进行调用了。

WeIdentity 源码分析 | 狗哥解码

4)CheckPermission

我们按照代码的书写顺序,首先来分析下checkPermission函数。

function checkPermission(         address addr,         uint operation     )          public          constant          returns (bool)      {         if (operation == MODIFY_AUTHORITY_ISSUER) {             if (adminRoleBearer[addr] || committeeMemberRoleBearer[addr]) {                 return true;             }         }         if (operation == MODIFY_COMMITTEE) {             if (adminRoleBearer[addr]) {                 return true;             }         }         if (operation == MODIFY_ADMIN) {             if (adminRoleBearer[addr]) {                 return true;             }         }         if (operation == MODIFY_KEY_CPT) {             if (authorityIssuerRoleBearer[addr]) {                 return true;             }         }         return false;     } 

从该函数的代码片段里可以看出,它做的主要工作其实就是接收两个参数:address、operation,然后再去判断该address所代表的role是否具备operation所代表的权限。

下面我们就实际调用一下。

我们将部署合约时所用的地址填入,再从200、201、202、203中随意选一个数字填入。(四个数字代表着不同权限)

WeIdentity 源码分析 | 狗哥解码

然后点击call,来调用一下。

WeIdentity 源码分析 | 狗哥解码

调用之后,结果是true。为什么这里是true呢?原因则在于代码最上面的构造函数。

WeIdentity 源码分析 | 狗哥解码

这里我们去修改一下构造函数,把true全部改为false,再来重新部署一下,然后看一下调用结果。

WeIdentity 源码分析 | 狗哥解码

这时候调用结果就变成了false,也就代表着部署合约时的地址没有该权限。

5)AddRole

接下来我们就再来看一下addRole这个函数。

function addRole(         address addr,         uint role     )          public      {         if (role == ROLE_AUTHORITY_ISSUER) {             if (checkPermission(tx.origin, MODIFY_AUTHORITY_ISSUER)) {                 authorityIssuerRoleBearer[addr] = true;             }         }         if (role == ROLE_COMMITTEE) {             if (checkPermission(tx.origin, MODIFY_COMMITTEE)) {                 committeeMemberRoleBearer[addr] = true;             }         }         if (role == ROLE_ADMIN) {             if (checkPermission(tx.origin, MODIFY_ADMIN)) {                 adminRoleBearer[addr] = true;             }         }     } 

从代码片段的里,我们可以分析得到该函数的主要工作机制是:先判断我们要增加的是何种Role,然后再判断调用者是否具备增加该Role的权限,具备则增加。

分析完之后,我们依旧是进行调用来测试一下,由于这里增加新的Role需要权限,因此我们将前面修改的构造函数全部改回true,然后重新部署一下。

部署完成后,我们的这个address就拥有了所有的修改权限,这时,我们再通过https://vanity-eth.tk/ 生成一个新的以太坊地址。

生成之后,我们将该地址填入第一个参数,第二个参数从100、101、102中随意选一个。

WeIdentity 源码分析 | 狗哥解码

这里,我们第二个参数填的是100。

WeIdentity 源码分析 | 狗哥解码

然后我们点击transact,就生成了一条新的记录。

WeIdentity 源码分析 | 狗哥解码

我们再来通过前面的checkPermission测试一下是否添加成功了。

由于我们新增的role是authority类型,因此它应该具有的权限是MODIFY_KEY_CPT,所以我们的参数就填这两个。

WeIdentity 源码分析 | 狗哥解码

返回结果为true,说明我们新增成功了。

6)CheckRole与RemoveRole

剩下的CheckRole与RemoveRole由于它们和前面的CheckPermission与AddRole非常的相似,因此这里就不再做详细的阐述了。

总结

到这里,RoleController这个合约我们就基本分析完成了,整体来讲,它还是非常的简单易读的,功能也相对简单明了。

在分析完成RoleController与Weldentity两个相对独立的模块后,接下来我们将会沿着链条向下剖析剩余模块。

WeIdentity 源码分析 | 狗哥解码

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注