https://github.com/OpenZeppelin/openzeppelin-solidity/tree/master/contracts/access

access - Smart contracts that enable functionality that can be used for selective restrictions and basic authorization control functions. Includes address whitelisting and signature-based permissions management.

  • rbac - A library used to manage addresses assigned to different user roles and an example Role-Based Access Control (RBAC) interface that demonstrates how to handle setters and getters for roles and addresses.

代码解释:

Roles.sol

这里只是底层地实现说明某个地址是否有某个角色,关于角色的详细信息,比如角色的名字,则通过调用该库来实现,如例子RBAC.sol

pragma solidity ^0.4.;

/**
* @title Roles
* @author Francisco Giordano (@frangio)
* @dev Library for managing addresses assigned to a Role.(给一个地址分配一个角色)
* See RBAC.sol for example usage.(RBAC.sol是这个库的使用例子)
*/
library Roles {
struct Role {
mapping (address => bool) bearer;
} /**
* @dev give an account access to this role
*/
//声明为storage是因为形参味memory,声明原因是:一般调用为storage形参 _role= storage传入,这样改变_role的值才会值传递,使storage的传入值也改变
//⚠️形参声明为storage的函数要定义为internal或private
function add(Role storage _role, address _account)
internal
{
_role.bearer[_account] = true;
} /**
* @dev remove an account's access to this role
*/
function remove(Role storage _role, address _account)
internal
{
_role.bearer[_account] = false;
} /**
* @dev check if an account has this role
* // reverts
*/
function check(Role storage _role, address _account)
internal
view
{
require(has(_role, _account));
} /**
* @dev check if an account has this role
* @return bool
*/
function has(Role storage _role, address _account)
internal
view
returns (bool)
{
return _role.bearer[_account];
}
}

RBAC.sol(是使用Roles库的例子)

pragma solidity ^0.4.;

import "./Roles.sol";

/**
* @title RBAC (Role-Based Access Control)
* @author Matt Condon (@Shrugs)
* @dev Stores and provides setters and getters for roles and addresses.
* Supports unlimited numbers of roles and addresses.
* See //contracts/mocks/RBACMock.sol for an example of usage.
* This RBAC method uses strings to key roles. It may be beneficial
* for you to write your own implementation of this interface using Enums or similar.
*/
contract RBAC {
using Roles for Roles.Role; mapping (string => Roles.Role) private roles; event RoleAdded(address indexed operator, string role);
event RoleRemoved(address indexed operator, string role); /**
* @dev reverts if addr does not have role
* @param _operator address
* @param _role the name of the role,在这里为角色赋名
* // reverts
*/
function checkRole(address _operator, string _role)
public
view
{
roles[_role].check(_operator);
} /**
* @dev determine if addr has role
* @param _operator address
* @param _role the name of the role
* @return bool
*/
function hasRole(address _operator, string _role)
public
view
returns (bool)
{
return roles[_role].has(_operator);
} /**
* @dev add a role to an address
* @param _operator address
* @param _role the name of the role
*/
function _addRole(address _operator, string _role)
internal
{
roles[_role].add(_operator);//所以roles[_role].bearer[_operator]=true
emit RoleAdded(_operator, _role);
} /**
* @dev remove a role from an address
* @param _operator address
* @param _role the name of the role
*/
function _removeRole(address _operator, string _role)
internal
{
roles[_role].remove(_operator);
emit RoleRemoved(_operator, _role);
} /**
* @dev modifier to scope access to a single role (uses msg.sender as addr)
* @param _role the name of the role
* // reverts
*/
modifier onlyRole(string _role)
{
checkRole(msg.sender, _role);
_;
} /**
* @dev modifier to scope access to a set of roles (uses msg.sender as addr)
* @param _roles the names of the roles to scope access to
* // reverts
*
* @TODO - when solidity supports dynamic arrays as arguments to modifiers, provide this
* see: https://github.com/ethereum/solidity/issues/2467
*/
// modifier onlyRoles(string[] _roles) {
// bool hasAnyRole = false;
// for (uint8 i = 0; i < _roles.length; i++) {
// if (hasRole(msg.sender, _roles[i])) {
// hasAnyRole = true;
// break;
// }
// } // require(hasAnyRole); // _;
// }
}

contracts/examples/RBACWithAdmin.sol

就是加入了一个admin的角色,这个角色只能一个人拥有。该角色的权利很大,所以一定要根据下面的标准来写,以免出错

pragma solidity ^0.4.;

import "../access/rbac/RBAC.sol";

/**
* @title RBACWithAdmin
* @author Matt Condon (@Shrugs)
* @dev It's recommended that you define constants in the contract,
* like ROLE_ADMIN below, to avoid typos.
* @notice RBACWithAdmin is probably too expansive and powerful for your
* application; an admin is actually able to change any address to any role
* which is a very large API surface. It's recommended that you follow a strategy
* of strictly defining the abilities of your roles
* and the API-surface of your contract.
* This is just an example for example's sake.
*/
contract RBACWithAdmin is RBAC {
/**
* A constant role name for indicating admins.
*/
string private constant ROLE_ADMIN = "admin"; /**
* @dev modifier to scope access to admins
* // reverts
*/
modifier onlyAdmin()
{
checkRole(msg.sender, ROLE_ADMIN);
_;
} /**
* @dev constructor. Sets msg.sender as admin by default
*/
constructor()
public
{
_addRole(msg.sender, ROLE_ADMIN);
} /**
* @return true if the account is admin, false otherwise.
*/
function isAdmin(address _account) public view returns(bool) {
return hasRole(_account, ROLE_ADMIN);
} /**
* @dev add a role to an account
* @param _account the account that will have the role
* @param _roleName the name of the role
*/
function adminAddRole(address _account, string _roleName)
public
onlyAdmin
{
_addRole(_account, _roleName);
} /**
* @dev remove a role from an account
* @param _account the account that will no longer have the role
* @param _roleName the name of the role
*/
function adminRemoveRole(address _account, string _roleName)
public
onlyAdmin
{
_removeRole(_account, _roleName);
}
}

contracts/mocks/RBACMock.sol

就是又加入了一种角色advisor,这个角色可以多个人拥有

pragma solidity ^0.4.;

import "../examples/RBACWithAdmin.sol";

contract RBACMock is RBACWithAdmin {

  string internal constant ROLE_ADVISOR = "advisor";

  modifier onlyAdminOrAdvisor()
{
require(
isAdmin(msg.sender) ||
hasRole(msg.sender, ROLE_ADVISOR)
);
_;
} constructor(address[] _advisors)
public
{
_addRole(msg.sender, ROLE_ADVISOR); for (uint256 i = ; i < _advisors.length; i++) {
_addRole(_advisors[i], ROLE_ADVISOR);
}
} function onlyAdminsCanDoThis()
external
onlyAdmin
view
{
} function onlyAdvisorsCanDoThis()
external
onlyRole(ROLE_ADVISOR)
view
{
} function eitherAdminOrAdvisorCanDoThis()
external
onlyAdminOrAdvisor
view
{
} function nobodyCanDoThis()
external
onlyRole("unknown")
view
{
} // admins can remove advisor's role
function removeAdvisor(address _account)
public
onlyAdmin
{
// revert if the user isn't an advisor
// (perhaps you want to soft-fail here instead?)
checkRole(_account, ROLE_ADVISOR); // remove the advisor's role
_removeRole(_account, ROLE_ADVISOR);
}
}

()

contracts/ownership/Ownable.sol

pragma solidity ^0.4.;

/**
* @title Ownable
* @dev The Ownable contract has an owner address, and provides basic authorization control
* functions, this simplifies the implementation of "user permissions".
*/
contract Ownable {
address public owner; event OwnershipRenounced(address indexed previousOwner);
event OwnershipTransferred(
address indexed previousOwner,
address indexed newOwner
); /**
* @dev The Ownable constructor sets the original `owner` of the contract to the sender
* account.
*/
constructor() public {
owner = msg.sender;
} /**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(msg.sender == owner);
_;
} /**
* @dev Allows the current owner to relinquish(放弃) control of the contract. 现在的owner可以放弃对合约的控制
* @notice Renouncing to ownership will leave the contract without an owner.
* It will not be possible to call the functions with the `onlyOwner`
* modifier anymore.
*/
function renounceOwnership() public onlyOwner {
emit OwnershipRenounced(owner);
owner = address();
} /**
* @dev Allows the current owner to transfer control of the contract to a newOwner.owner将控制权转移
* @param _newOwner The address to transfer ownership to.
*/
function transferOwnership(address _newOwner) public onlyOwner {
_transferOwnership(_newOwner);
} /**
* @dev Transfers control of the contract to a newOwner.
* @param _newOwner The address to transfer ownership to.
*/
function _transferOwnership(address _newOwner) internal {
require(_newOwner != address());
emit OwnershipTransferred(owner, _newOwner);
owner = _newOwner;
}
}

contracts/cryptography/ECDSA.sol

有关的详细内容可以看本博客的椭圆曲线相关内容

pragma solidity ^0.4.;

/**
* @title Elliptic curve signature operations 椭圆曲线
* @dev Based on https://gist.github.com/axic/5b33912c6f61ae6fd96d6c4a47afde6d这是一个完整的例子
* TODO Remove this library once solidity supports passing a signature to ecrecover.因为在solidity中ecrecover函数还不能直接输入signature,所以下面要自己将r,s,v分离出来
* See https://github.com/ethereum/solidity/issues/864建议实现能够直接将signature传递给ecrecover函数,而不是还要转成v,r,s
*/ library ECDSA { /**
* @dev Recover signer address from a message by using their signature
* @param _hash bytes32 message, the hash is the signed message. What is recovered is the signer address.
* @param _signature bytes signature, the signature is generated using web3.eth.sign()
*/
function recover(bytes32 _hash, bytes _signature)//将signature的r,v,s分离出来,传到ecrecover函数中
internal
pure
returns (address)
{
bytes32 r;
bytes32 s;
uint8 v; // Check the signature length
if (_signature.length != ) {//签名有65bits
return (address());
} // Divide the signature in r, s and v variables
// ecrecover takes the signature parameters, and the only way to get them
// currently is to use assembly.
// solium-disable-next-line security/no-inline-assembly
assembly {
r := mload(add(_signature, ))//这是因为前32位存储了_signature变量的长度信息
s := mload(add(_signature, ))
v := byte(, mload(add(_signature, )))//v代表的是版本,有27和28两种,byte默认表示byte1,即1byte
} // Version of signature should be 27 or 28, but 0 and 1 are also possible versions
if (v < ) {
v += ;
} // If the version is correct return the signer address
if (v != && v != ) {
return (address());
} else {
// solium-disable-next-line arg-overflow
return ecrecover(_hash, v, r, s);
}
} /**
* toEthSignedMessageHash
* @dev prefix a bytes32 value with "\x19Ethereum Signed Message:"
* and hash the result
*/
function toEthSignedMessageHash(bytes32 _hash)
internal
pure
returns (bytes32)
{
// 32 is the length in bytes of hash,
// enforced by the type signature above
return keccak256(
abi.encodePacked("\x19Ethereum Signed Message:\n32", _hash)
);
}
}
 

contracts/access/SignatureBouncer.sol

这里的角色是bouncer,保镖

pragma solidity ^0.4.;

import "../ownership/Ownable.sol";
import "../access/rbac/RBAC.sol";
import "../cryptography/ECDSA.sol"; /**
* @title SignatureBouncer
* @author PhABC, Shrugs and aflesher
* @dev Bouncer allows users to submit a signature as a permission to do an action.使用者通过签名来允许进行某行为
* If the signature is from one of the authorized bouncer addresses, the signature如果是一个被授权的bouncer地址进行了签名,该签名也是有效的
* is valid. The owner of the contract adds/removes bouncers.
* Bouncer addresses can be individual servers signing grants or different (bouncer地址可能是一个签署授权的单独服务器
* users within a decentralized club that have permission to invite other members. 或者是在一个去中心化团体中且有着权利邀请其他成员的不同使用者
* This technique is useful for whitelists and airdrops; instead of putting all
* valid addresses on-chain, simply sign a grant of the form 通过对一个有效的bouncer地址签署授权而不是把所有有效的地址都放到链上
* keccak256(abi.encodePacked(`:contractAddress` + `:granteeAddress`)) using a valid bouncer address.
* Then restrict access to your crowdsale/whitelist/airdrop using the //这样你后面就可以通过修饰器来限制一些操作了
* `onlyValidSignature` modifier (or implement your own using _isValidSignature).
* In addition to `onlyValidSignature`, `onlyValidSignatureAndMethod` and
* `onlyValidSignatureAndData` can be used to restrict access to only a given method
* or a given method with given parameters respectively.
* See the tests Bouncer.test.js for specific usage examples.
* @notice A method that uses the `onlyValidSignatureAndData` modifier must make the _signature
* parameter the "last" parameter. You cannot sign a message that has its own
* signature in it so the last 128 bytes of msg.data (which represents the 这后面的128 bytes就是签名,当一个信息已经有了自己的签名,这后面再进行的签名将会被忽略
* length of the _signature data and the _signaature data itself) is ignored when validating.
* Also non fixed sized parameters make constructing the data in the signature
* much more complex. See https://ethereum.stackexchange.com/a/50616 for more details.
*/
contract SignatureBouncer is Ownable, RBAC {
using ECDSA for bytes32; // Name of the bouncer role.
string private constant ROLE_BOUNCER = "bouncer";
// Function selectors are 4 bytes long, as documented in
// https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector
uint256 private constant METHOD_ID_SIZE = ;
// Signature size is 65 bytes (tightly packed v + r + s), but gets padded to 96 bytes
uint256 private constant SIGNATURE_SIZE = ; /**
* @dev requires that a valid signature of a bouncer was provided
*/
modifier onlyValidSignature(bytes _signature)
{
require(_isValidSignature(msg.sender, _signature));
_;
} /**
* @dev requires that a valid signature with a specifed method of a bouncer was provided
*/
modifier onlyValidSignatureAndMethod(bytes _signature)
{
require(_isValidSignatureAndMethod(msg.sender, _signature));
_;
} /**
* @dev requires that a valid signature with a specifed method and params of a bouncer was provided
*/
modifier onlyValidSignatureAndData(bytes _signature)
{
require(_isValidSignatureAndData(msg.sender, _signature));
_;
} /**
* @dev Determine if an account has the bouncer role.
* @return true if the account is a bouncer, false otherwise.
*/
function isBouncer(address _account) public view returns(bool) {
return hasRole(_account, ROLE_BOUNCER);
} /**
* @dev allows the owner to add additional bouncer addresses
*/
function addBouncer(address _bouncer)
public
onlyOwner
{
require(_bouncer != address());
_addRole(_bouncer, ROLE_BOUNCER);
} /**
* @dev allows the owner to remove bouncer addresses
*/
function removeBouncer(address _bouncer)
public
onlyOwner
{
_removeRole(_bouncer, ROLE_BOUNCER);
} /**
* @dev is the signature of `this + sender` from a bouncer?
* @return bool
*/
function _isValidSignature(address _address, bytes _signature)
internal
view
returns (bool)
{
return _isValidDataHash(
keccak256(abi.encodePacked(address(this), _address)),//将所给的参数打包再一起进行ABI编码,然后进行hash
_signature //该_signature是对`this + sender`内容的签名,所以上面的hash是那样的
);
} /**
* @dev is the signature of `this + sender + methodId` from a bouncer?
* @return bool
*/
function _isValidSignatureAndMethod(address _address, bytes _signature)
internal
view
returns (bool)
{
bytes memory data = new bytes(METHOD_ID_SIZE);//4个字节bytes
for (uint i = ; i < data.length; i++) {
data[i] = msg.data[i];
}
return _isValidDataHash(
keccak256(abi.encodePacked(address(this), _address, data)),
_signature
);
} /**
* @dev is the signature of `this + sender + methodId + params(s)` from a bouncer?
* @notice the _signature parameter of the method being validated must be the "last" parameter
* @return bool
*/
function _isValidSignatureAndData(address _address, bytes _signature)
internal
view
returns (bool)
{
require(msg.data.length > SIGNATURE_SIZE);
bytes memory data = new bytes(msg.data.length - SIGNATURE_SIZE);//msg.data中除掉签名的内容96bytes就是数据data,签名的内容放在msg.data的最后面
for (uint i = ; i < data.length; i++) {
data[i] = msg.data[i];
}
return _isValidDataHash(
keccak256(abi.encodePacked(address(this), _address, data)),
_signature
);
} /**
* @dev internal function to convert a hash to an eth signed message
* and then recover the signature and check it against the bouncer role
* @return bool
*/
function _isValidDataHash(bytes32 _hash, bytes _signature)
internal
view
returns (bool)
{
address signer = _hash //这两个都是ECDSA.sol里的函数
.toEthSignedMessageHash()//convert a hash to an eth signed message
.recover(_signature);//调用库的recover函数,得到签名的公钥,即地址signer
return isBouncer(signer);
}
}

contracts/access/Whitelist.sol

声明白名单,即在这个名单中的address是可信赖的,可进行一些操作

pragma solidity ^0.4.;

import "../ownership/Ownable.sol";
import "../access/rbac/RBAC.sol"; /**
* @title Whitelist
* @dev The Whitelist contract has a whitelist of addresses, and provides basic authorization control functions.
* This simplifies the implementation of "user permissions".
*/
contract Whitelist is Ownable, RBAC { // Name of the whitelisted role.
string private constant ROLE_WHITELISTED = "whitelist"; /**
* @dev Throws if operator is not whitelisted.
* @param _operator address
*/
modifier onlyIfWhitelisted(address _operator) {
checkRole(_operator, ROLE_WHITELISTED);
_;
} /**
* @dev add an address to the whitelist
* @param _operator address
* @return true if the address was added to the whitelist, false if the address was already in the whitelist
*/
function addAddressToWhitelist(address _operator)
public
onlyOwner
{
_addRole(_operator, ROLE_WHITELISTED);
} /**
* @dev Determine if an account is whitelisted.
* @return true if the account is whitelisted, false otherwise.
*/
function isWhitelisted(address _operator)
public
view
returns (bool)
{
return hasRole(_operator, ROLE_WHITELISTED);
} /**
* @dev add addresses to the whitelist
* @param _operators addresses
* @return true if at least one address was added to the whitelist,
* false if all addresses were already in the whitelist
*/
function addAddressesToWhitelist(address[] _operators)
public
onlyOwner
{
for (uint256 i = ; i < _operators.length; i++) {
addAddressToWhitelist(_operators[i]);
}
} /**
* @dev remove an address from the whitelist
* @param _operator address
* @return true if the address was removed from the whitelist,
* false if the address wasn't in the whitelist in the first place
*/
function removeAddressFromWhitelist(address _operator)
public
onlyOwner
{
_removeRole(_operator, ROLE_WHITELISTED);
} /**
* @dev remove addresses from the whitelist
* @param _operators addresses
* @return true if at least one address was removed from the whitelist,
* false if all addresses weren't in the whitelist in the first place
*/
function removeAddressesFromWhitelist(address[] _operators)
public
onlyOwner
{
for (uint256 i = ; i < _operators.length; i++) {
removeAddressFromWhitelist(_operators[i]);
}
} }

openzeppelin-solidity/contracts的代码学习——access的更多相关文章

  1. openzeppelin-solidity/contracts的代码学习——payment

    payment - A collection of smart contracts that can be used to manage payments through escrow arrange ...

  2. Objective-C代码学习大纲(3)

    Objective-C代码学习大纲(3) 2011-05-11 14:06 佚名 otierney 字号:T | T 本文为台湾出版的<Objective-C学习大纲>的翻译文档,系统介绍 ...

  3. u-boot代码学习内容

    前言  u-boot代码庞大,不可能全部细读,只能有选择的读部分代码.在读代码之前,根据韦东山教材,关于代码学习内容和深度做以下预先划定. 一.Makefile.mkconfig.config.mk等 ...

  4. Access教程 Access学习 Access培训 Access QQ交流集中地

    Access教程 Access学习 Access培训 Access QQ交流集中地 http://www.office-cn.net/plugin.php?id=zstm_qqgroup:index ...

  5. ORB-SLAM2 论文&代码学习 ——Tracking 线程

    本文要点: ORB-SLAM2 Tracking 线程 论文内容介绍 ORB-SLAM2 Tracking 线程 代码结构介绍 写在前面 上一篇文章中我们已经对 ORB-SLAM2 系统有了一个概览性 ...

  6. ORB-SLAM2 论文&代码学习 —— 单目初始化

    转载请注明出处,谢谢 原创作者:Mingrui 原创链接:https://www.cnblogs.com/MingruiYu/p/12358458.html 本文要点: ORB-SLAM2 单目初始化 ...

  7. ORB-SLAM2 论文&代码学习 —— LocalMapping 线程

    转载请注明出处,谢谢 原创作者:Mingrui 原创链接:https://www.cnblogs.com/MingruiYu/p/12360913.html 本文要点: ORB-SLAM2 Local ...

  8. Learning Memory-guided Normality代码学习笔记

    Learning Memory-guided Normality代码学习笔记 记忆模块核心 Memory部分的核心在于以下定义Memory类的部分. class Memory(nn.Module): ...

  9. 3.1.5 LTP(Linux Test Project)学习(五)-LTP代码学习

    3.1.5 LTP(Linux Test Project)学习(五)-LTP代码学习 Hello小崔 ​ 华为技术有限公司 Linux内核开发 2 人赞同了该文章 LTP代码学习方法主要介绍两个步骤, ...

随机推荐

  1. 【手记】解决“未能创建 SSL/TLS 安全通道”异常

    之前写了一个桌面程序,程序会间歇性访问某个https接口,一直用的好好的,今天突然报错了,异常就发生在访问接口的地方,曰“请求被中止,未能创建 SSL/TLS 安全通道.”,另外有台电脑也有跑该程序, ...

  2. 【Core】在mvc使用EF

    引用DLL: 继续上一篇的内容我们来添加EF实体: 首先:工具> NuGet程序包管理器>程序包管理器控制台: Install-Package Microsoft.EntityFramew ...

  3. [PHP] 算法-请找出带环链表的环的入口结点的PHP实现

    给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null 1.找链表倒数第k个结点,输入一个链表,输出该链表中倒数第k个结点.第一个指针走(k-1)步,到达第k个节点,两个指针同时往后 ...

  4. 在UWP中实现自己的MVVM设计模式

    其实写这篇博文的时候我是拒绝的,因为这牵扯到一个高大上的东西——"框架".一说起这个东西,很多朋友就感觉有点蒙了,尤其是编程新手.因为它不像在代码里面定义一个变量那么显而易见,它是 ...

  5. 为什么90%的CTO 都做不好绩效管理

    ​ 十多年从业经历,从 2001 年开始带团队到现在,我几乎经历过所有的 IT 角色.2010 年,我随创始团队筹建国美在线至今,经历了从几百单到现在日均百万订单,从只有家电品类到现在全品类.金融.大 ...

  6. deepin使用笔记-解决蓝牙设备开机自动开启的问题

    我的邮箱地址:zytrenren@163.com欢迎大家交流学习纠错! 1.安装蓝牙驱动管理 #apt-get install blueman 2.打开蓝牙驱动管理,关闭设备 3.关闭蓝牙开机启动服务 ...

  7. spring项目获取ServletContext

    (1)生命周期 ServletContext中的属性的生命周期从创建开始,到服务器关闭而 (2).获取ServletContext 1.request获取servletContext ServletC ...

  8. 通过webpack2从0开始配置自己的vue项目 1

    PS 阅读者需要node基础.webpack原理知识.vue基础 安装node 这个网上很多教程 打开终端 创建项目 npm init 全局安装: cnpm i webpack webpack-dev ...

  9. SD从零开始71 业务信息仓库(BW)

    SD从零开始71 业务信息仓库(BW)概念 在线事务处理的环境OLTP Environment 在事务处理中,我们不断地填充用于跟踪我们的业务流程的数千个不同步骤的特定的表: 例如,销售凭证行条目来自 ...

  10. C#中禁止跨线程直接访问控件

    C#中禁止跨线程直接访问控件,InvokeRequired是为了解决这个问题而产生的,当一个控件的InvokeRequired属性值为真时,说明有一个创建它以外的线程想访问它.此时它将会在内部调用ne ...