【技术分析】简单了解 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 ...
随机推荐
- 从SOA到RPC、SOAP、REST-copy
从SOA说起SOA是把项目拆成组件,每个组件暴露出服务,强调的是服务的复用.SOA架构实现不依赖于技术,因此能够被各种不同的技术实现.例如:SOAP, RPC,REST,DCOM,CORBA,OPC- ...
- w3cschool-微信小程序开发文档-组件
https://www.w3cschool.cn/weixinapp/sp6z1q8q.html 微信小程序视图容器 view view 视图容器. 属性 类型 默认值 必填 说明 最低版本 hove ...
- JavaScript操作addEventListener监听触发事件
JavaScript 的 addEventListener 方法允许你为指定的 HTML 元素添加事件监听器.以下是一些常见的事件类型,可以使用 addEventListener 来监听它们: 1,点 ...
- linux:项目上线
服务器选择 项目上线服务器必须是外网服务器 真实服务器 成本过高.多用于测试 云服务器 阿里云.腾讯云.百度云.华为云.盛大云.新浪云.亚马逊云等 官网:阿里云 1.注册/登录后 2.支付成功即可![ ...
- Java中用Deque接口代替Stack接口完成栈功能
之前在有需要用到栈功能的时候,都是通过使用Stack接口完成的,也就是: 1 Stack<T> stack = new Stack<>() 但今天突然发现,Java Doc里建 ...
- C#中DevExpress的GridControl相关表格的属性总结
这里用到了Dev中的GridControl表格做数据查询展示,要求字号大一些,单行选中深色显示 // grid1 this.grid1.Dock = System.Windows.Forms.Dock ...
- oracle 删除过期归档脚本
一.定时任务 crontab -e 编辑 每周6凌晨3点执行脚本 0 3 * * 6 . /home/oracle/scripts/arch_delete_before_60days_arch.sh ...
- Java获取数据库的列名、列数、标题、类型等信息, ResultSetMetaData
import java.sql.*; public class jdbcTest { public static void main(String[] args) throws ClassNotFou ...
- MacOS配置Homebrew
Homebrew笔记 1. 介绍 官网:https://brew.sh/ 对于习惯了使用命令来完成一切的程序员来说,安装软件这种小事,自然是能够用命令解决,就不用图形界面选择.但是在 Linux 中, ...
- WinForm 进度条显示进度百分比
参考: https://blog.csdn.net/zhuimengshizhe87/article/details/20640157 WinForm中显示进度条百分比有多种方式: 1. 添加 Lab ...