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. 清除电脑垃圾.bat

    echo.title delete cachecolor 0aecho.echo please enter any key start.....@echo offecho execuing delet ...

  2. 微信公众号开发--.Net Core实现微信消息加解密

    1:准备工作 进入微信公众号后台设置微信服务器配置参数(注意:Token和EncodingAESKey必须和微信服务器验证参数保持一致,不然验证不会通过). 2:基本配置 设置为安全模式 3.代码实现 ...

  3. [android] androidPN开源项目介绍

    打开androidPN项目,会看到server和client两份代码 server部分 找到server的代码,开启服务,双击 bin/run.bat ,服务启动后监听127.0.0.1:7070端口 ...

  4. Spring中四种实例化bean的方式

    本文主要介绍四种实例化bean的方式(注入方式) 或者叫依赖对象实例化的四种方式.上面的程序,创建bean 对象,用的是什么方法 ,用的是构造函数的方式 (Spring 可以在构造函数私有化的情况下把 ...

  5. Mysql无法选取非聚合列

    教程所示图片使用的是 github 仓库图片,网速过慢的朋友请移步>>> (原文)Mysql 无法选取非聚合列. 更多讨论或者错误提交,也请移步. 1. 前言 最近升级博客,给文章页 ...

  6. jQuery动画切换引擎插件Velocity.js

    Velocity.js 官网 Velocity.js实现弹出式相框 慕课网 极棒的jquery动画切换引擎插件Velocity.js jQ库 (function($){ // 普通调用 /*$('#d ...

  7. JS数组迭代方法

    先说 every()和 some(),它们都用于查询数组中的项是否满足某个条件. every(): var numbers = [1,2,3,4,5,4,3,2,1]; var everyResult ...

  8. 2018-01-11 Antlr4的分析错误处理

    中文编程知乎专栏原文地址 (前文通用型的中文编程语言探讨之一: 高考, 即使是这"第一步", 即使一切顺利达到列出的功能恐怕也需要个人数年的业余时间. 看到不少乎友都远更有资本和实 ...

  9. MVC与单元测试实践之健身网站(五)-系统信息、前台入口

    Fit项目停滞了一段时间,现在继续吧.上一篇完成了动作文本和配图的添加.编辑等内容.接下来要完成的是后台的最后一个模块:系统信息:以及前台的入口:关于注册.登录.修改密码等. 一 系统信息 a) 用户 ...

  10. HTML5文件API之FileReader

    在文件上传之前,我们总想预览一下文件内容,或图片样子,html5 中FileReader正好提供了2种方法,可以在不上传文件的情况下,预览文件内容. 图片预览:readAsDataURL(file); ...