【技术分析】简单了解 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 ...
随机推荐
- IM开发者的零基础通信技术入门(十三):为什么手机信号差?一文即懂!
[来源申明]本文引用了微信公众号"网优雇佣军"的<是谁偷走了我家的手机信号?>文章内容.为了更好的内容呈现,下文在引用和收录时内容有改动,转载时请注明原文来源信息,尊重 ...
- 基于Redis有序集合实现滑动窗口限流
滑动窗口算法是一种基于时间窗口的限流算法,它将时间划分为若干个固定大小的窗口,每个窗口内记录了该时间段内的请求次数.通过动态地滑动窗口,可以动态调整限流的速率,以应对不同的流量变化. 整个限流可以概括 ...
- linux获取当前用户名
linux环境下获取当前登录用户名 方法1: whoami 命令 1 $whoami 2 输出:username 3 $sudo whoami 4 输出:root 注意:通过不同用户权限执行获取的用 ...
- vue实现自定义音乐播放器
项目中遇到了,让实现一个音乐播放器的功能.修改其样式要求自定义,切需要有,进度条,时间,开关,应用于H5需要兼容ios与android.简单看一下如图播放器 完成代码 audioCom.vue < ...
- Solution -「CTSC 2017」「洛谷 P3772」游戏
\(\mathscr{Description}\) 有 \(n\) 个随机真值 \(x_{1..n}\), 已知 \(P(x_1=1)=p_1\), 对于 \(2\le i\le n\), \(P ...
- 使用postgis数据库进行多边形裁切线
背景:有一份polyline的基础数据,有一个多边形,求出多边形内的所有polyline PostGIS参考手册: http://postgis.net/docs/reference.html 1.p ...
- OV7670寄存器说明
I2C读出来的内容的地址,比datasheet给出的小9? add- 0x0 = 0x0add- 0x1 = 0x76add- 0x2 = 0x73add- 0x3 = 0x4add- 0x4 = 0 ...
- 基于同态加密的PSI开源库-1
下面介绍一个PSI的开源库,还原论文:CCS2017:Fast Private Set Intersection from Homomorphic Encryption和CCS2018:Labeled ...
- Kotlin:【set集合】集合创建、可变集合mutableSetOf、集合转换(List转换成Set,去掉重复元素)、distinct快捷去重函数、数组
- vue3.5保证你看得明明白白
子组件中设置默认属性 <template> <div class="child-page"> <h1>我是子组件</h1> < ...