当我们开发一个智能合约,但是里面有一些函数不能随便让别人调用,只能“拥有权限”的管理员能够调用,那么这时候我们会用到权限管理机制。

实现起来也很简单,设置一个 owner 变量,通过 modifier onlyOwner() 检查调用 onlyOwnerCanCall() 的地址是否等于预先设置好的 woner,这样就可以保证只有 owner 能够调用这个函数。

contract AccessControl {
address private owner; constructor() {
owner = msg.sender;
} modifier onlyOwner() {
require(msg.sender == owner, "Caller is not the owner");
_;
} function onlyOwnerCanCall() public onlyOwner {
// ...
}
}

由于权限控制这个机制被广泛应用在不同的场景中,为了避免重复开发以及保证实现质量,开发者可以从 openzeppelin 的标准库中使用 openzeppelin-contracts/contracts/access 目录下的标准库进行实现。

目前为 5.2.0 版本:https://github.com/OpenZeppelin/openzeppelin-contracts/tree/v5.2.0/contracts/access

主要分为 3 种方案:

  1. Ownable:只要单一的 owner 权限,owner 权限可以转移,放弃(置为 0 地址)。
  2. Ownable2Step:在 Ownable 基础上避免了将 owner 权限转移到了错误的地址导致权限丢失,Ownable2Step 在权限转移这个环节,添加了接受权限的地址需要调用 acceptOwnership() 进行领取的步骤。
  3. AccessControl:不再采用单一的 owner 进行权限管理,而是更细粒度地细分到了多种权限账户。

在接下来的文章中会对 AccessControl 进行展开介绍。

AccessControl

代码实现:https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.2.0/contracts/access/AccessControl.sol

AccessControl 中存储所有管理员信息的全局变量是 _roles ,其次是代表默认管理员的 DEFAULT_ADMIN_ROLE

权限检查

当需要对某个函数进行调用权限的限制时,可以通过添加 modifier onlyRole(bytes32 role) 的方式来检查 msg.sender 是否满足指定权限角色 ROLE 的要求。

function privilegedFunctions() public onlyRole(ROLE){...}

modifier onlyRole(bytes32 role) 会调用以下的函数来进行检查

modifier onlyRole(bytes32 role) {
_checkRole(role);
_;
} function _checkRole(bytes32 role) internal view virtual {
_checkRole(role, _msgSender());
} function _checkRole(bytes32 role, address account) internal view virtual {
if (!hasRole(role, account)) {
revert AccessControlUnauthorizedAccount(account, role);
}
} function hasRole(bytes32 role, address account) public view virtual returns (bool) {
return _roles[role].hasRole[account];
}

当用户调用需要 ROLE 权限的函数时,modifier onlyRole(bytes32 role) 会检查 _roles[ROLE].hasRole[mag.sender] 是否为 true

权限角色管理

而当需要通过权限管理员来管理权限角色时:

  1. 通过 grantRole(bytes32 role, address account) 来授予 account 地址 role 权限角色。
  2. 通过 revokeRole(bytes32 role, address account) 来移除 account 地址 role 权限角色。
function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {
return _roles[role].adminRole;
} function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
_grantRole(role, account);
} function _grantRole(bytes32 role, address account) internal virtual returns (bool) {
if (!hasRole(role, account)) {
_roles[role].hasRole[account] = true;
emit RoleGranted(role, account, _msgSender());
return true;
} else {
return false;
}
} function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
_revokeRole(role, account);
} function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {
if (hasRole(role, account)) {
_roles[role].hasRole[account] = false;
emit RoleRevoked(role, account, _msgSender());
return true;
} else {
return false;
}
}

当需要添加 ROLE 的权限时,则需要通过 onlyRole(getRoleAdmin(role) 检查 _roles[_roles[role].adminRole].hasRole[mag.sender] 是否为 true。也就是说每一个权限角色(ROLE)的管理员,都是对应着另一个权限角色(ROLE_ADMIN)。

默认管理员

那么权限角色有管理员,管理员还有他自己的管理员,那岂不是无穷尽也?这个时候就用到 DEFAULT_ADMIN_ROLE 角色了,由于它的值被设定为 0x00,所以只要你不为某一个权限角色设置 adminRole,那么 adminRole 的值就会指向 DEFAULT_ADMIN_ROLE(0x00)

应用实例

根据上面的内容,实现了一个简单的 Demo 协助读者理解(仅供参考,请勿用作生产代码)。

contract RoleDemo is AccessControl {
// Define roles
bytes32 public constant ADMIN_ROLE = keccak256("ADMIN_ROLE");
bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); constructor() {
// Grant DEFAULT_ADMIN_ROLE to contract deployer
_grantRole(DEFAULT_ADMIN_ROLE, msg.sender);
// Grant ADMIN_ROLE to contract deployer
_grantRole(ADMIN_ROLE, address(0x01));
// Grant MINTER_ROLE to contract deployer
_grantRole(MINTER_ROLE, address(0x02)); // Set ADMIN_ROLE as the admin role for MINTER_ROLE
_setRoleAdmin(MINTER_ROLE, ADMIN_ROLE);
} // Function can only be called by addresses with DEFAULT_ADMIN_ROLE
function defultAdminFunction() public onlyRole(DEFAULT_ADMIN_ROLE) {
// Default admin function implementation
} // Function can only be called by addresses with ADMIN_ROLE
function adminFunction() public onlyRole(ADMIN_ROLE) {
// Admin function implementation
} // Function can only be called by addresses with MINTER_ROLE
function minterFunction() public onlyRole(MINTER_ROLE) {
// Minter function implementation
}
}

这段代码实现了以下的功能:

  1. 设置默认管理员 DEFAULT_ADMIN_ROLE 为合约部署者 deployer
  2. 设置 address(0x02)MINTER_ROLE 权限角色
  3. 设置 address(0x01)MINTER_ROLE 权限的管理员 ADMIN_ROLE,可以移除或添加 MINTER_ROLE 权限角色。
  4. DEFAULT_ADMIN_ROLE 默认作为 ADMIN_ROLE 的管理员,可以移除或添加 ADMIN_ROLE 权限角色。

【技术分析】简单了解 AccessControl的更多相关文章

  1. 蓝牙协议分析(7)_BLE连接有关的技术分析

    转自:http://www.wowotech.net/bluetooth/ble_connection.html#comments 1. 前言 了解蓝牙的人都知道,在经典蓝牙中,保持连接(Connec ...

  2. iOS直播的技术分析与实现

    HTTP Live Streaming直播(iOS直播)技术分析与实现 发布于:2014-05-28 13:30阅读数:12004 HTTP Live Streaming直播(iOS直播)技术分析与实 ...

  3. 横向技术分析C#、C++和Java优劣

    转自横向技术分析C#.C++和Java优劣 C#诞生之日起,关于C#与Java之间的论战便此起彼伏,至今不辍.抛却Microsoft与Sun之间的恩怨与口角,客观地从技术上讲,C#与Java都是对传统 ...

  4. 美链BEC合约漏洞技术分析

    这两天币圈链圈被美链BEC智能合约的漏洞导致代币价值几乎归零的事件刷遍朋友圈.这篇文章就来分析下BEC智能合约的漏洞 漏洞攻击交易 我们先来还原下攻击交易,这个交易可以在这个链接查询到. 我截图给大家 ...

  5. 【Python量化投资】基于技术分析研究股票市场

    一 金融专业人士以及对金融感兴趣的业余人士感兴趣的一类就是历史价格进行的技术分析.维基百科中定义如下,金融学中,技术分析是通过对过去市场数据(主要是价格和成交量)的研究预测价格方向的证券分析方法. 下 ...

  6. [IC]Lithograph(1)光刻技术分析与展望

    文章主体转载自: 1.zol摩尔定律全靠它 CPU光刻技术分析与展望 2.wiki:Extreme ultraviolet lithography 3.ITRS 2012 1. 光刻技术组成和关键点 ...

  7. 转: HTTP Live Streaming直播(iOS直播)技术分析与实现

    http://www.cnblogs.com/haibindev/archive/2013/01/30/2880764.html HTTP Live Streaming直播(iOS直播)技术分析与实现 ...

  8. Fabric 和 Sawtooth 技术分析(下)

    http://blog.talkingdata.com/?p=6172 在前一篇文章(Fabric和Sawtooth技术分析(上))中,我们着重跟大家分享了 Fabric 相关的内容,在本篇文章中,我 ...

  9. 【转】HTTP Live Streaming直播(iOS直播)技术分析与实现

    HTTP Live Streaming直播(iOS直播)技术分析与实现 不经意间发现,大半年没写博客了,自觉汗颜.实则2012后半年,家中的事一样接着一样发生,实在是没有时间.快过年了,总算忙里偷闲, ...

  10. Ripple 20:Treck TCP/IP协议漏洞技术分析

    本文由“合天智汇”公众号首发,作者:b1ngo Ripple 20:Treck TCP/IP协议漏洞技术分析 Ripple20是一系列影响数亿台设备的0day(19个),是JSOF研究实验室在Trec ...

随机推荐

  1. DVWA靶场Insecure CAPTCHA(不安全验证)漏洞所有级别通关教程及源码审计

    Insecure CAPTCHA(不安全验证) Insecure CAPTCHA(不安全验证)漏洞指的是在实现 CAPTCHA(完全自动化公共图灵测试区分计算机和人类)机制时,未能有效保护用户输入的验 ...

  2. C Primer Plus 第6版 第四章 编程练习参考答案

    编译环境VS Code+WSL GCC 源码请到文末下载 /*第1题*************************/ #include<stdio.h> int main() { ch ...

  3. Mac上安装mongoDB详细教程

    Mac OSX 平台安装 MongoDB MongoDB 提供了 OSX 平台上 64 位的安装包,你可以在官网下载安装包. 下载地址:https://www.mongodb.com/download ...

  4. w3cschool-Spring Security

    https://www.w3cschool.cn/springsecurity/na1k1ihx.html Spring Security,这是一种基于 Spring AOP 和 Servlet 过滤 ...

  5. w3cschool-Struts2 概述

    Struts2 概述 Struts2 是目前较为普及和成熟的基于MVC设计模式的web应用程序框架,它不仅仅是Struts1 的升级版本,更是一个全新的Struts架构.最初,是以WebWork框架和 ...

  6. 利用mybatis拦截器记录sql,辅助我们建立索引(二)

    背景 上一篇中讲述了mybatis的mapper初始化过程和执行过程,这篇再讲讲具体的拦截器的使用,以实现记录sql到持久化存储,通过分析这些sql,我们就能更方便地建立索引. 利用mybatis拦截 ...

  7. Kotlin:【针对空安全管理的操作】安全调用操作符、使用带let的安全调用、非空断言操作符(感叹号操作符)、使用if判断null值情况、使用空合并操作符(类似三元表达式)

     具体使用:

  8. jdk 5.0 新增的foreach循环(用于遍历集合、数组)

    使用 foreach 循环遍历集合元素 Java 5.0 提供了 foreach 循环迭代访问 Collection和数组. 遍历操作不需获取Collection或数组的长度,无需使用索引访问元素 ...

  9. WebClient 获取不到请求体如何破解?

    起初在开发过程中,我遇到了一个困扰我的问题:当我将对象转换为JSON时,得到的结果与最终传给第三方接口的请求体并不一致.这个问题导致我在进行加密操作时出现了错误,因为加密的过程是基于请求体的,而请求体 ...

  10. 在 PyTorch 中理解词向量,将单词转换为有用的向量表示

    你要是想构建一个大型语言模型,首先得掌握词向量的概念.幸运的是,这个概念很简单,也是本系列文章的一个完美起点. 那么,假设你有一堆单词,它可以只是一个简单的字符串数组. animals = [&quo ...