【技术分析】简单了解 AccessControl
当我们开发一个智能合约,但是里面有一些函数不能随便让别人调用,只能“拥有权限”的管理员能够调用,那么这时候我们会用到权限管理机制。
实现起来也很简单,设置一个 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 种方案:
- Ownable:只要单一的 owner 权限,owner 权限可以转移,放弃(置为 0 地址)。
- Ownable2Step:在 Ownable 基础上避免了将 owner 权限转移到了错误的地址导致权限丢失,Ownable2Step 在权限转移这个环节,添加了接受权限的地址需要调用 acceptOwnership() 进行领取的步骤。
- AccessControl:不再采用单一的 owner 进行权限管理,而是更细粒度地细分到了多种权限账户。
在接下来的文章中会对 AccessControl 进行展开介绍。
AccessControl
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。

权限角色管理
而当需要通过权限管理员来管理权限角色时:
- 通过
grantRole(bytes32 role, address account)来授予 account 地址 role 权限角色。 - 通过
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
}
}
这段代码实现了以下的功能:
- 设置默认管理员
DEFAULT_ADMIN_ROLE为合约部署者deployer - 设置
address(0x02)为MINTER_ROLE权限角色 - 设置
address(0x01)为MINTER_ROLE权限的管理员ADMIN_ROLE,可以移除或添加MINTER_ROLE权限角色。 DEFAULT_ADMIN_ROLE默认作为ADMIN_ROLE的管理员,可以移除或添加ADMIN_ROLE权限角色。
【技术分析】简单了解 AccessControl的更多相关文章
- 蓝牙协议分析(7)_BLE连接有关的技术分析
转自:http://www.wowotech.net/bluetooth/ble_connection.html#comments 1. 前言 了解蓝牙的人都知道,在经典蓝牙中,保持连接(Connec ...
- iOS直播的技术分析与实现
HTTP Live Streaming直播(iOS直播)技术分析与实现 发布于:2014-05-28 13:30阅读数:12004 HTTP Live Streaming直播(iOS直播)技术分析与实 ...
- 横向技术分析C#、C++和Java优劣
转自横向技术分析C#.C++和Java优劣 C#诞生之日起,关于C#与Java之间的论战便此起彼伏,至今不辍.抛却Microsoft与Sun之间的恩怨与口角,客观地从技术上讲,C#与Java都是对传统 ...
- 美链BEC合约漏洞技术分析
这两天币圈链圈被美链BEC智能合约的漏洞导致代币价值几乎归零的事件刷遍朋友圈.这篇文章就来分析下BEC智能合约的漏洞 漏洞攻击交易 我们先来还原下攻击交易,这个交易可以在这个链接查询到. 我截图给大家 ...
- 【Python量化投资】基于技术分析研究股票市场
一 金融专业人士以及对金融感兴趣的业余人士感兴趣的一类就是历史价格进行的技术分析.维基百科中定义如下,金融学中,技术分析是通过对过去市场数据(主要是价格和成交量)的研究预测价格方向的证券分析方法. 下 ...
- [IC]Lithograph(1)光刻技术分析与展望
文章主体转载自: 1.zol摩尔定律全靠它 CPU光刻技术分析与展望 2.wiki:Extreme ultraviolet lithography 3.ITRS 2012 1. 光刻技术组成和关键点 ...
- 转: HTTP Live Streaming直播(iOS直播)技术分析与实现
http://www.cnblogs.com/haibindev/archive/2013/01/30/2880764.html HTTP Live Streaming直播(iOS直播)技术分析与实现 ...
- Fabric 和 Sawtooth 技术分析(下)
http://blog.talkingdata.com/?p=6172 在前一篇文章(Fabric和Sawtooth技术分析(上))中,我们着重跟大家分享了 Fabric 相关的内容,在本篇文章中,我 ...
- 【转】HTTP Live Streaming直播(iOS直播)技术分析与实现
HTTP Live Streaming直播(iOS直播)技术分析与实现 不经意间发现,大半年没写博客了,自觉汗颜.实则2012后半年,家中的事一样接着一样发生,实在是没有时间.快过年了,总算忙里偷闲, ...
- Ripple 20:Treck TCP/IP协议漏洞技术分析
本文由“合天智汇”公众号首发,作者:b1ngo Ripple 20:Treck TCP/IP协议漏洞技术分析 Ripple20是一系列影响数亿台设备的0day(19个),是JSOF研究实验室在Trec ...
随机推荐
- Python多分类Logistic回归详解与实践
在机器学习中,Logistic回归是一种基本但非常有效的分类算法.它不仅可以用于二分类问题,还可以扩展应用于多分类问题.本文将详细介绍如何使用Python实现一个多分类的Logistic回归模型,并给 ...
- x86平台SIMD编程入门(2):通用指令
1.重解释转换 虽然128位的XMM寄存器在硬件上只是256位YMM寄存器的下半部分,但在C++中它们是不同的类型.有一些intrinsic函数可以将它们重新解释为不同的类型,如下表所示,行代表源类型 ...
- IdentityServer4中的核心类
启动配置器IIdentityServerBuilder 可以把它理解为一个IServiceCollection的容器,它商品有几个扩展方法,方便我们用来注册ids使用到的相关服务,为啥不直接扩展ISe ...
- UWP 读写文件
List<Pics> pics = new List<Pics>(); for (int i = 0; i < 2000; i++) { pics.Add(new Pic ...
- 安装Docker及相关容器
一,Docker简介百科说:Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化,容器是完全使用沙箱 ...
- SpringCloud(1)---入门篇
SpringCloud理解篇 一.微服务概述 1.什么是微服务 目前的微服务并没有一个统一的标准,一般是以业务来划分将传统的一站式应用,拆分成一个个的服务,彻底去耦合,一个微服务就是单功能业务,只做一 ...
- Linux 提权指南
知屋漏者在宇下,知政失者在草野,知经误者在诸子. 导航 壹 - 密码搜寻 贰 - Sudo 命令 叁 - SUID/SGID 特权 肆 - 计划任务 伍 - 文件/目录 陆 - Linux 内核 柒 ...
- Cuckoo Hash
最近在看APSI中,涉及到了一些hash技术(朴素hash,置换hash,布谷鸟hash),Hash 技术是 PSI 协议中优化通信复杂度和计算杂度的重要工具之一,现在系统的认识一下! 更多关于哈希函 ...
- C 2017笔试题
1.下面程序的输出结果是 int x=3; do { printf("%d\n",x-=2); }while(!(--x)); 输出:1 -2 解析:x初始值为3,第一次循环中运行 ...
- 萌新赛 sprintf漏洞
首先是个.git源码源码泄露,用githack回复一下源码 源码 <?php $pass=sprintf("and pass='%s'",addslashes($_GET[' ...