5.4.1 账户权限相关概念
权限
EOS采用父子分层的权限结构,低级权限(子权限)由高级权限(父权限)派生而来,父权限拥有子权限所有的能力。子权限能做的事父权限也能做,但是反过来,父权限能做的事,子权限不一定能做。
- owner 是最高等级权限,拥有owner权限就意味着拥有账户的所有权,我们可以把owner理解为超级管理员权限。
- active 是owner的子权限,主要用来发送交易、投票或者进行高级别的账户修改操作。
权重
权限拥有者在权限中的重要程度,具体以不小于1的整数表示。
阈值
执行该权限的最低权重的临界值,大于此临界值就可以执行该权限了。
账户
执行操作的执行体,当一个账户被创建时,就具备了两种基本权限(permission)。每个权限绑定在一个公钥或多个公钥上,还可以绑定到另一个有效的账户的权限(permission)上。
账户权限由权限(permission)、对应公钥或另一个账户的权限(嵌套权限)、权重(weight)以及阈值(threshold)四个部分组成,账户下的权限结构如下:
5.4.2 交易鉴权过程
当执行一笔交易时,通过权限验证,可以开始执行,分成两步:
- 获取账户权限中的公钥,通过钱包找到私钥,然后通过私钥对交易进行签名;
- 从签名串中解出公钥,进行数字签名认证(查看公钥是否在账户权限中存在),如果存在则获取此公钥的权重,并比较权重是否大于权限的阈值,若大于阈值则鉴权通过;如果账户权限是多重嵌套权限,则需要把每个权限鉴权通过后的权重相加,把最后权重的总和与权限阈值做比较;
我们通过一个例子来说明权限的验证过程:
账户account1加载token合约,执行account1转账给account2,5个SDF代币,由account1执行;
./cleos set contract account1 ../../contracts/eosio.token -p [email protected]
./cleos push action account1 transfer ‘[ "account1", "account2", "5.00 SDF", "m" ]‘ -p [email protected]
创建账户时,系统同时会把账户下默认的权限设置好,写入chainbase数据库中,但可以通过命令修改账户下的权限的公钥,嵌套关系,权重,阈值;
比如:账户account1的权限表如下表所示:
因为账户account1的权限表中存在嵌套关系:[email protected],则也需要账户account2的权限表,如下表所示:
签名交易过程
做操作push action时,会最终打包成交易,接下来需要对交易做签名。
首先需要从账户account1中获取权限中的所有公钥,根据account1的权限表得到的required_keys如下:
{
"EOS8FERV2Qd6UQ5GvgB1VtAJmwg4C2WZjR6HMxPyfSJVYacNc8DPC",
"EOS8hSFZmpPrXvnT9YgT94hDfQ9S3vVddxpMvDBZL2MWL1XTD6aLK"
}
其次,通过required_keys列表在钱包中找到对应的私钥,通过私钥对交易数据签名,生成两个个签名交易串signatures如下;
{
"SIG_K1_K55WNdUGH3nvhqUmUXmZcYP7wvNs5sA3RGFrdgsoz1LtAfWSfWd4GTxAFvn66dFkzhGNBrPK4xPWvLcCnwLZzhDy8DhNXd",
"SIG_K1_Y98JhdUGH3nvhqUmUXmZcYP7wvNdfgergrdrNJkjjkiUJjLKfWSfWd4GTxAFvn66dFgfdBrPK4xPWvLJIHIU4jI6iIiopL"
}
权限验证过程
先了解下公私钥的作用:
Private key: 5JaGpdrxRstRLZ9yNaCsAVhLmvYcAsyLRZ1BJiy8pEmDMZmNtij
Public key: EOS8FERV2Qd6UQ5GvgB1VtAJmwg4C2WZjR6HMxPyfSJVYacNc8DPC
EOS系统采用的是DSA+ECC加密签名算法,主要用于数字签名和验证;
私钥主要用于签名,公钥用于验证;
所以,首先需要从签名串中解出公钥,作为权限验证的输入条件,根据上面的签名结果signatures,解出公钥列表provided_keys如下:
{
"EOS8FERV2Qd6UQ5GvgB1VtAJmwg4C2WZjR6HMxPyfSJVYacNc8DPC",
"EOS8hSFZmpPrXvnT9YgT94hDfQ9S3vVddxpMvDBZL2MWL1XTD6aLK"
}
看下account1账户下的信息:
看下account2账户下的信息:
修改account1账户下的信息:
修改后的account1账户下的信息:
account1转账给account2,5个SDF代币:
现在我们分析下执行转账的具体鉴权过程:
我们在代码中关键点添加了一些打印信息,打印结果如下图:
trx.actions : 交易的所有action,需要验证的所有action
provided_keys :签名串中解出的公钥列表,用于数字签名认证,与权限对应的公钥做比对
permisions_to_satisfy : 需要验证的权限列表
authority_key : Key类型的权限列表
authority_accounts : 嵌套类型的权限列表
current weight : 鉴权过程中的当前权重,用做与阈值做比对的
current threshold : 鉴权需要的阈值
1.account1的active权限,阈值为2,权限部分由两部分组成:
(1).公钥key权限,EOS8hSFZmpPrXvnT9YgT94hDfQ9S3vVddxpMvDBZL2MWL1XTD6aLK权限,权重为1;
(2).嵌套的账户account2权限,权重为1;account2的active权限对应EOS8FERV2Qd6UQ5GvgB1VtAJmwg4C2WZjR6HMxPyfSJVYacNc8DPC权限;
2.依次验证active权限:
(1).验证公钥key权限,系统会拿出active的key权限,对应的公钥是EOS8hSFZmpPrXvnT9YgT94hDfQ9S3vVddxpMvDBZL2MWL1XTD6aLK,然后拿这个公钥在provided_keys中查找是否存在,如果存在,则判断对应的权重是否大于等于阈值,若满足,则鉴权通过,若不满足,则需要加上嵌套账户account2权限的权重,求总和后,判断是否满足;
(2).验证嵌套账户account2权限,账户account2的active的key权限,对应的公钥是EOS8FERV2Qd6UQ5GvgB1VtAJmwg4C2WZjR6HMxPyfSJVYacNc8DPC,然后拿这个公钥在provided_keys中查找是否存在,如果存在,则加上步骤一对应的权限,求出和,判断总的权重是否大于等于account1的active权限的阈值,若满足,则鉴权通过,若不满足,则鉴权失败;
从上面的打印结果可以看出,鉴权经过了两次判断,因为account1的active权限的阈值为2,而账户的的两个权限的权重都为1,所以需要两次;
5.4.3 源码分析鉴权过程
从上面的鉴权过程,我们可以知道,鉴权接口需要交易打包的actions和交易签名解出来的公钥列表;
看下action的定义:
从签名串中解出公钥:
recover_keys()函数会调用下面的代码,如图:
在push_transaction()会做鉴权验证,接口为check_authorization():
在check_authorization()中做验证时,分为三步:
(1).验证是否满足最小权限;
(2).把满足最小权限的权限加入到待验证的权限列表中;
(3).对权限列表中的权限依次验证;
把满足最小权限的权限加入到待验证的权限列表中后,看下 permissions_to_satisfy 的定义:
map<permission_level, fc::microseconds> permissions_to_satisfy;
开始验证权限:
因为weight_tally_visitor结构体重载了()操作符,所以在调用 visitor(permission_level_weight{permission, 1}) 时,会调用weight_tally_visitor结构体()操作符的重载函数;
在satisfied()函数时,会按权限类型分类验证;
先看下权限的分类定义:
递归调用key类型()的重载函数,判断权限是否满足权重大于等于阀值,如果大于等于阈值,则鉴权成功;
5.4.4 总结
总结:
1.有多个或多种权限的鉴权过程就是判断满足多个或多种权限对应的权重的总和是否大于等于执行者的权限阈值;
2.所有的嵌套的账户权限的验证,最终都转化为验证最小单位Key类型的权限验证;
3.最小单位Key类型权限的验证即对交易签名串的签名认证(证明是某个账户发起的交易),也就是验证该权限对应的公钥是否在签名串解出的公钥列表中存在;
链接
http://www.3heu.club:8008/
https://www.jianshu.com/p/0b7365ea43fe
https://blog.csdn.net/arm_snow/article/details/90318052
原文地址:https://blog.51cto.com/14267585/2396721