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. Redis Eval Script

    简介 从Redis 2.6 版本开始,内嵌支持 Lua 环境.通过使用EVAL或EVALSHA命令可以使用 Lua 解释器来执行脚本. EVAL和EVALSHA的使用是差不多的(下面有讲区别). EV ...

  2. Docker 安装MySQL5.7(三)

    Docker 安装MySQL5.7 1.搜索docker镜像(可以看到搜索的结果,这个结果是按照一定的星级评价规则排序的) docker search mysql 2.拉取docker的mysql镜像 ...

  3. JavaSE List集合

    我们掌握了Collection接口的使用后,再来看看Collection接口中的子接口和实现类,他们都具备那些特性呢? 接下来,我们一起学习Collection中的常用几个子接口: ​ java.ut ...

  4. 【Linux】Centos之安装Nginx及注意事项

    相关内容链接 [Linux]nginx常用命令 [nginx]详细配置说明 1.Nginx的简单说明 a.  Nginx是一个高性能的HTTP和反向代理服务器,也是一个IMAP/POP3/SMTP服务 ...

  5. What is The Rule of Three?

    Question: What does copying an object mean? What are the copy constructor and the copy assignment op ...

  6. 小程序和PHP学习笔记 ----- 不定期更新。

    学习tp5和小程序过程需要记住的重点记录 1,box-sizing: border-box; 规定两个并排的带边框的框 border-box 为元素设定的宽度和高度决定了元素的边框盒. 就是说,为元素 ...

  7. cf666E. Forensic Examination(广义后缀自动机 线段树合并)

    题意 题目链接 Sol 神仙题Orz 后缀自动机 + 线段树合并 首先对所有的\(t_i\)建个广义后缀自动机,这样可以得到所有子串信息. 考虑把询问离线,然后把\(S\)拿到自动机上跑,同时维护一下 ...

  8. 【20190129】CSS-定位问题记录

    很多情况下我在写div的时候都不会把高度写死,而是用子元素撑开高度的方式,但是如果子元素设置了浮动或者position绝对定位,就相当于把子元素从文档流中拿出来了,这时父元素的高度就不能被子元素撑开了 ...

  9. JMeter 查看结果树监听器响应数据中文显示乱码解决方法

    查看结果树监听器响应数据中文显示乱码解决方法 by:授客 QQ:1033553122   问题描述 使用监听器-查看结果树(View Results Tree Listener)过程中发现,响应数据面 ...

  10. 使用windows命令和iconv.exe批量转换文件编码

    iconv是知名的开源跨平台编码转换库,iconv.exe是iconv库在windows下的命令行工具,iconv.exe的一般用法:iconv.exe -f gbk -t utf-8 gbk.txt ...