Solidity简介:ACL和事件。 [第2部分]

本文是上一篇讨论数据契约的文章的系列文章的下一篇。先前讨论中的示例合同是从称为“ ACLContract”的合同继承而来的,但是我们尚未使用ACLContract提供的任何功能,因为我们尚未看到如何使用ACL(访问控制列表)和“事件”来交付访问控制和访问记录工具.

访问控制是一种机制,用于提供对资源的选择性限制访问。信息技术中有各种各样的访问控制模型,其中大多数集中在试图访问资源的用户或“主体”周围。在某些情况下,资源本身可以定义对它的访问,但是我们将不再赘述。为了我们的目的,我们将坚持两种访问控制–基于角色和基于属性.

Solidity简介:ACL和事件。 [第2部分]

遗产:

由于访问控制是一项应在某种程度上可插入的功能,因此我们将利用继承为您的域合同提供此功能。牢固继承使用复制代码机制将“超合同”代码植入“分包合同”中,其中超合同是可继承合同,而分合同则是继承合同。 Solidity还支持多态的面向对象编程(OOPS)概念,在该概念中,合同实例可以作为其任何子类实例的两倍加倍.

我们的ACL(访问控制列表)合同将由域合同继承,并将提供数据访问控制功能。域合同将只需要用它将继承的ACL合同方法来包围其资源调用.

ACL合同:

ACL合同的基本前提是提供创建/管理一个或多个用户列表的方法,并提供可以根据该列表检查任何特定用户的方法。我们的假设是,合同的每个用户都是“地址”类型–地址是一种特殊类型的实体变量,代表您的钱包或帐户地址。将其用作用户凭证是有意义的,因为用户仅通过其帐户地址访问合同。我们还可以假设来自某个地址的呼叫是真实的,因为只有在用户可以访问该帐户的私钥的情况下才能进行该呼叫,这是以太坊真实性的基本前提.  

合同的基本模板将具有两个实例变量:

 

向公共所有者讲话;

面向[]公众用户;

所有者地址将是合同的创建者。我们将在构造函数调用期间实例化它。这是一个合理的假设,因为所有者只应部署合同,除非我们需要将所有者职能委托给另一个地址,我们将在合同中对此做出规定,如我们所见.

因此,如果合同称为ACLContract,则以下代码将实例化所有者地址,并使所有者成为用户之一.

函数ACLContract(){

所有者= msg.sender;

users.push(所有者);

}

实例化合同后,我们将需要一些操作方法来管理用户列表。味精是一种特殊的实体对象,用于保存有关事务的调用方或发送方的数据。在这种情况下,部署者帐户将是部署合同的交易的调用者,因此我们会将所有者地址分配给该调用者的地址.

函数addUser(地址用户){

如果(msg.sender!=所有者)抛出;

users.push(用户);

}

函数getIthUser(uint i)常量返回(地址){

返回用户[i];

}

函数getUserCount()常量返回(uint){

返回users.length;

}

函数deleteIthUser(uint i){

如果(msg.sender!=所有者)抛出;

删除用户[i];

}

客户将使用这些方法来管理用户列表。我们看到只有所有者才能使用此检查来管理列表:

如果(msg.sender!=所有者)抛出;

因此,此代码将调用者的地址与所有者进行匹配,并在不匹配的情况下使事务失败并抛出异常。在我们进一步进行操作之前,我们需要稍微研究一下引发异常,因为这是万一访问控制机制失败时我们将采取的主要保护措施.

例外情况:

异常是可靠地指示事务中错误情况的机制。异常的结果是当前调用被停止,并且事务的所有作用都被撤销。如果异常发生在调用堆栈中,则该异常将在堆栈中返回到第一个调用方。目前,无法从异常中恢复过来,因为发生的部分状态更改可能不安全继续进行交易,因此为了保持交易的原子性,所有更改都将还原.

有两种异常,运行时异常和用户提供的异常.

如果代码遇到在Solidity文档中列出的12种情况(请参阅文档–太多且过多,无法在此处粘贴),则运行时异常会自动发生,这些异常大多数是在执行语句/事务的状态下可能发生的异常成功了.

用户提供的异常正在代码中手动引发。有两种创建方法–使用条件为require的结果为假,或使用明确的抛出。我们正在使用条件抛出,并且我们希望这样做将恢复事务处理的效果,并在违反所设置的访问控制的情况下使调用失败.

回到我们的ACLContract,我们已经完成了用户列表的创建以及管理该列表所需的方法。我们所做的事情有一些警告,可以创建两个列表-一个用于只读用户,另一个用于读取和写入用户.

事实上,以太坊区块链中存在的任何数据本质上都是公共的,因此创建只读用户是没有意义的,因为任何人都可以看到该数据,但是如果数据访问是以某种方式加密的话允许将其链接到用户帐户,那么我们可以考虑一个只读用户。以太坊社区中正在进行有关使以太坊区块链隐私变得友好的讨论,关于如何做到这一点有很多建议.

如果我们可以得出这样的假设:通过上述任何提议或通过自定义方案,我们都能够加密我们的数据,并且能够确保仅在整个合同代码中都可以进行数据访问,那么我们将发现创建数据很有用两个列表–只读用户和读写用户。该代码与我们为单阵列用户编写的代码非常相似。每个列表只需要四种管理方法(readUsers和writeUsers).

创建访问控制:

要根据访问控制列表审核用户,我们需要将其与地址列表进行匹配。我们可以创建一个简单的方法来接受用户地址,并尝试将其与列表匹配:

函数isUser(候选地址,字符串方法)返回(布尔值){

for(uint8 i = 0;我 < users.length; i ++){

如果(用户[i] ==候选人){

返回true;

}

}

返回false;

}

如果我们在列表中找到用户,则逻辑很容易理解,如果为true,则退出循环,如果列表中的元素用完,则返回false。稍后将在谈论事件记录用户访问和尝试访问的结果时使用传递的字符串方法参数.

使用事件记录访问:

安全原则中定义的基本概念是AAA(身份验证,授权和审核).

当用户启动某个帐户的交易时,以太坊提供身份验证。假定用户拥有该帐户,因为他能够使用该帐户来发起交易。该验证的责任是导致用户使用其帐户密码进行身份验证是在以太坊节点客户端级别完成的.

AAA的授权部分已由ACLContract实施,其中实施了基于角色的访问控制.

AAA的第三部分是审核-审核的要求是应记录用户访问权限。为此,我们将使用事件.

团结事件:

事件就像合同的普通实例变量一样,它们可以像任何变量一样被继承。事件用于将值返回给客户端,以防返回值列表,但是我们仅将其作为在区块链上创建日志的一种方式进行检查。使用提供给他们的参数从区块链的一部分“触发”事件时的事件.

为了实现一个日志事件,我们将定义一个Event变量:

事件LogAccess(由索引的地址,由uint索引的accessTime,字符串方法,字符串desc);

此事件将在我们的访问控制方法isUser()中使用,以记录其结果正在尝试的访问.

函数isUser(候选地址,字符串方法)返回(布尔值){

for(uint8 i = 0;我 < users.length; i ++){

如果(用户[i] ==候选人){

LogAccess(候选人,现在,方法, "成功访问");

返回true;

}

}

LogAccess(候选者,现在,方法, "访问失败");

返回false;

}

 

该事件正在为访问帐户(候选),时间(现在),资源(方法)和结果(失败访问,成功访问)参数化。我们使用字符串来描述结果,但建议使用uint常数以简化搜索.

该事件将在每次访问isUser()时触发,并将访问记录在区块链上以进行审核。可以通过web3客户端调用访问事件,我们将在下一部分中看到.

推杆 ACL合同 使用:

我们创建的合同可以被任何其他合同继承,以重用其提供的ACL列表。我们的数据合约正在使用构造继承它.

抵销DataContract是ACLContract {

要使用ACL工具,我们将使用isUser()拦截协定中的方法调用:

函数updateCustomer(uint索引,字符串名称){

如果(isUser(msg.sender, "updateCustomer")){

如果(索引 > 数)

customer [index] .name =名称;

}

否则扔

}

函数updateCustomerStatus(uint索引,uint状态){

如果(isUser(msg.sender, "updateCustomer")){

如果(索引 > 数)

customer [index] .status =状态;

}

否则扔

}

函数createCustomer(

使用者编号,

字串名称,

出生日期,

uint social){

如果(isUser(msg.sender, "createCustomer")){

customer [count] =客户(id,姓名,出生日期,社交,待处理);

数++;

}

否则扔

}

我们仅对更新数据的方法提供访问控制限制,如果我们在合同中对客户数据进行了加密,我们也可以对其读取功能实施限制.

合同无法访问它创建的事件,因此要访问事件,我们将需要web3客户端来创建调用:

假设ABI已签约ABI,地址是其在区块链上的位置.

var DataContract = web3.eth.contract(abi).at(address);

var eventLogs = DataContract.allEvents()。get();

console.log(eventLogs);

除了上面的用法以外,事件还有很多其他内容,我们的目的是为了进行审计而检索它们.

基于属性的访问控制:

可以使用另一种类型的访问控制,其中通过属性标识授权用户。我们正在对此进行讨论,以举例说明我们在导言中谈到的“基于属性的访问控制”。这只是isUser()调用的一个变体:

函数isUserAuthorized(候选地址,字符串方法)返回(布尔值){

for(uint8 i = 0;我 < users.length; i ++){

如果(候选人。 > 100){

LogAccess(msg.sender,现在,方法, "成功访问");

返回true;

}

}

LogAccess(msg.sender,now,method, "访问失败");

返回false;

}

这是一个非常琐碎的示例,其中授权用户是余额醚大于100的用户.

Mike Owergreen Administrator
Sorry! The Author has not filled his profile.
follow me