简介 基于角色的访问控制是软件系统的安全需求,旨在为数百个用户提供访问。虽然这种需求通常在企业软件和操作系统中实现,但对以太坊区块链的处理并不多。 本文旨在展示我们如何在以太坊区块链的Solidity中实现基于角色的访问控制,并教您如何应用在自己的区块链。 当将供应链设计为有向无环图时,我们意识到需要动态地确定谁可以向图中的每个节点添加信息。从现实世界的角度来看,如果您拥有一家制造工厂,您可能希望装配线上的所有操作员都能够用他们自己的帐户记录他们已经组装了一个零件。 OpenZeppelin是我在Solidity开发中使用的金标准,它有一个roles.sol合同,用于在erc721.sol合同中实现诸如minter和burner等角色。不幸的是,这些实现不允许在运行时创建新角色,如果您想使用单独的角色控制对每个单独令牌的访问,则需要创建新角色。 本文旨在展示如何为以太坊区块链构建基于角色的访问控制系统。根据我们的要求从头开始编写RBAC合同,然后从OpenZeppelin中找到了相同想法的版本,它具有几乎相同的方法。为了可重用性,我尽可能地重构我的代码以遵循它们的命名法。 在以下各节中,我将介绍: 1. 我们进入访问系统的设计要求; 2. 智能合约的实施; 3. 测试案例; 4. 状态变换法的gas利用; 5. 还有一些完善的想法。 概念设计 我对RBAC系统的想法很简单。 1. 角色将由数字标识符标识,如Unix中的组。 2. 角色可以动态创建。 3. 每个角色存储用户的地址。 4. 每个角色都会有一个关联的第二个角色,这是唯一允许添加或删除用户的角色。 如果您是使用OpenZeppelin中的Roles.sol和RBAC.sol合同,则需要注意Roles.sol仅实现在角色内生效的操作,而在角色外部发生的操作在RBAC.sol或访问中实现/roles/*Role.sol收缩,包括在创建角色时存储角色的数据结构。 在我的实现中,我根据我们的用例做了一些决策: · 角色结构中包含一个描述字符串,结构本身存储在一个数组中。数组中每个角色结构的位置用作标识符。有一种使用映射来存储角色,但我发现这里没有必要。 · 每个角色在实例化时接收我们指定为其管理角色的另一个角色的标识符,并且在实例化之后不能修改该角色。此管理员角色是唯一可以为此角色添加和删除承载者的角色。 出于安全性和一致性的原因,您可以从角色中删除承载,但没有方法可以从系统中完全删除角色。 pragma solidity ^0.5.0; /** * @title RBAC * @author Alberto Cuesta Canada * @notice Implements runtime configurable Role Based Access Control. */ contract RBAC { event RoleCreated(uint256 role); event BearerAdded(address account, uint256 role); event BearerRemoved(address account, uint256 role); uint256 constant NO_ROLE = 0; /** * @notice A role, which will be used to group users. * @dev The role id is its position in the roles array. * @param description A description for the role. * @param admin The only role that can add or remove bearers from * this role. To have the role bearers to be also the role admins * you should pass roles.length as the admin role. * @param bearers Addresses belonging to this role. */ struct Role { string description; uint256 admin; mapping (address => bool) bearers; } /** * @notice All roles ever created. */ Role[] public roles; /** * @notice The contract constructor, empty as of now. */ constructor() public { addRootRole("NO_ROLE"); } /** * @notice Create a new role that has itself as an admin. * msg.sender is added as a bearer. * @param _roleDescription The description of the role created. * @return The role id. */ function addRootRole(string memory _roleDescription) public returns(uint256) { uint256 role = addRole(_roleDescription, roles.length); roles[role].bearers[msg.sender] = true; emit BearerAdded(msg.sender, role); } /** * @notice Create a new role. * @param _roleDescription The description of the role created. * @param _admin The role that is allowed to add and remove * bearers from the role being created. * @return The role id. */ function addRole(string memory _roleDescription, uint256 _admin) public returns(uint256) { require(_admin <= roles.length, "Admin role doesn't exist."); uint256 role = roles.push( Role({ description: _roleDescription, admin: _admin }) ) - 1; emit RoleCreated(role); return role; } /** * @notice Retrieve the number of roles in the contract. * @dev The zero position in the roles array is reserved for * NO_ROLE and doesn't count towards this total. */ function totalRoles() public view returns(uint256) { return roles.length - 1; } /** * @notice Verify whether an account is a bearer of a role * @param _account The account to verify. * @param _role The role to look into. * @return Whether the account is a bearer of the role. */ function hasRole(address _account, uint256 _role) public view returns(bool) { return _role < roles.length && roles[_role].bearers[_account]; } /** * @notice A method to add a bearer to a role * @param _account The account to add as a bearer. * @param _role The role to add the bearer to. */ function addBearer(address _account, uint256 _role) public { require( _role < roles.length, "Role doesn't exist." ); require( hasRole(msg.sender, roles[_role].admin), "User can't add bearers." ); require( !hasRole(_account, _role), "Account is bearer of role." ); roles[_role].bearers[_account] = true; emit BearerAdded(_account, _role); } /** * @notice A method to remove a bearer from a role * @param _account The account to remove as a bearer. * @param _role The role to remove the bearer from. */ function removeBearer(address _account, uint256 _role) public { require( _role < roles.length, "Role doesn't exist." ); require( hasRole(msg.sender, roles[_role].admin), "User can't remove bearers." ); require( hasRole(_account, _role), "Account is not bearer of role." ); delete roles[_role].bearers[_account]; emit BearerRemoved(_account, _role); } } 测试 我喜欢公开测试智能合约,既展示了操作案例,又能对代码的可靠性提供了一些信心。 Contract: RBAC RBAC addRootRole creates a role. hasRole returns false for non existing roles. hasRole returns false for non existing bearerships. addRootRole adds msg.sender as bearer. addRole doesn’t add msg.sender with admin role. addBearer reverts on non existing roles. addBearer reverts on non authorized users. addBearer reverts if the bearer belongs to the role. addBearer adds a bearer to a role. removeBearer reverts on non existing roles. removeBearer reverts on non authorized users. removeBearer reverts if the bearer doesn't belong to the role. removeBearer removes a bearer from a role. 为了回应之前的反馈,我现在还使用eth-gas-reporter的gas使用报告。
结论 —- 编译者/作者:不详 玩币族申明:玩币族作为开放的资讯翻译/分享平台,所提供的所有资讯仅代表作者个人观点,与玩币族平台立场无关,且不构成任何投资理财建议。文章版权归原作者所有。 |
基于角色的以太坊区块链访问控制
2019-07-10 不详 来源:网络
LOADING...
相关阅读:
- 瑞波首席执行官布拉德·加林豪斯(Brad Garlinghouse)反对Coinbase的“不政2020-10-26
- DeFi新玩法 | 人人都能创建保险合约,一分钟了解Protekt Protocol想做什么2020-10-26
- Pionex派网携手币安,全新交易工具开启「区块链券商」新赛道 - 律动B2020-10-26
- Binance Launchpad添加了游戏宠物宇宙Axie Infinity2020-10-26
- 大多数欧洲专业投资者购买了数字资产或计划2020-10-26