跳到主要内容

AccessControl

1. 角色管理员的能力

在 OpenZeppelin 的 AccessControl 里: 每个 role(角色,类型是 bytes32)都有一个 管理员角色(roleAdmin)。 拥有 roleAdmin 的账户,可以:

grantRole(role, account):给任意地址授予该角色。 revokeRole(role, account):从任意地址收回该角色。

所以: 谁拥有某个角色的管理员角色,就能控制这个角色的分配和收回。 DEFAULT_ADMIN_ROLE,它充当所有角色的默认管理员角色。 具有此角色的帐户将能够管理任何其他角色,除非_setRoleAdmin使用 选择新的管理员角色。

2. 被授予角色后的能力

一个地址一旦被 grantRole 成功,就拥有了该角色。 在合约代码里,凡是用 onlyRole(ROLE_X) 修饰的方法,该地址就可以调用。

例如:

function specialThing() external onlyRole(ROLE_MANAGER) {
// 只有 ROLE_MANAGER 的地址才能执行
}

3. 特别说明

DEFAULT_ADMIN_ROLE:默认就是所有角色的管理员(除非用 _setRoleAdmin 修改)。所以一般部署时 _grantRole(DEFAULT_ADMIN_ROLE, deployer),相当于让部署者是“超级管理员”。 角色的管理员角色本身也可以被修改:比如 _setRoleAdmin(ROLE_NORMAL, ROLE_MANAGER) 表示以后只有 ROLE_MANAGER 才能分发/收回 ROLE_NORMAL。 注意权限断层:如果不小心把一个角色的管理员设成某个没人持有的角色,这个角色就“失控”了——再也没人能 grant/revoke 它。

一句话总结

角色管理员负责分配和回收角色。 角色持有者就能执行该角色被限定的操作。

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

// https://docs.openzeppelin.com/contracts/5.x/api/access#AccessControl
import "@openzeppelin/contracts/access/AccessControl.sol";

contract Roles is AccessControl{
bytes32 public constant ROLE_MANAGER = keccak256("ROLE_MANAGE");
bytes32 public constant ROLE_NORMAL = keccak256("ROLE_NORMAL");


// DEFAULT_ADMIN_ROLE 定义为常量 0x00(全零 bytes32),它是“万物之管理员”,默认是所有角色的管理员。
// _msgSender() 来自 Context(AccessControl 继承了 Context),本质上就是 msg.sender 的封装(方便将来支持元交易/受信转发)。
constructor(){
_grantRole(DEFAULT_ADMIN_ROLE, _msgSender());
}

// _setRoleAdmin(bytes32 role, bytes32 adminRole)
// 设置adminRole为role的管理员角色。
function setRoleAdmin() external onlyRole(DEFAULT_ADMIN_ROLE){
_setRoleAdmin(ROLE_NORMAL, ROLE_MANAGER);
}

function normalThing() external onlyRole(ROLE_NORMAL){
}
function specialThing() external onlyRole(ROLE_MANAGER){

}
}

Ownable.sol

提供简单的访问权控制,其中有一个帐户(所有者),可以授予其对特定功能的专属访问权限。

import "@openzeppelin/contracts/access/Ownable.sol";

两个方法

renounceOwnership 放弃权限,直接把权限给0地址 transferOwnership 转让权限

最小应用

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import "@openzeppelin/contracts/access/Ownable.sol";

contract SimpleOwnable is Ownable {

uint256 public value;

// 构造函数:部署者自动成为 owner
constructor() Ownable(msg.sender) {}

// 只有 owner 才能调用
function setValue(uint256 _value) external onlyOwner {
value = _value;
}
}

OwnableUpgradeable

Ownable的可升级版

import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";

使用案例

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";

contract SimpleOwnableUpgradeable is OwnableUpgradeable {

uint256 public value;

// 代替 constructor 的初始化函数
function initialize(address initialOwner) external initializer {
__Ownable_init(initialOwner);
}

// 只有 owner 才能调用
function setValue(uint256 _value) external onlyOwner {
value = _value;
}
}
📢 Share this article