­

第十章 Fisco Bcos 權限控制下的數據上鏈實操演練

  • 2019 年 10 月 3 日
  • 筆記

 

想了解相關區塊鏈開發,技術提問,請加QQ群:538327407

 

一、目的

 

前面已經完成fisco bcos 相關底層搭建、sdk使用、控制台、webase中間件平台等系列實戰開發,

本次進行最後一個部分,體系化管理區塊鏈底層,建立有序的底層控管制度,實現權限化管理。

完成:鏈管理、系統管理、數據上鏈操作等。

其中數據上鏈分為:合約版本上鏈、crudService 版本上鏈等操作。

二、準備工作:

 

在進行之前,我們首先要了解一下,fisco bcos 的底層權限系統介紹。

https://mp.weixin.qq.com/s/QJNk71w4o_cGX2O-1aW29Q

 

三、設計理念差異

 

1、底層默認是可以部署合約,只有一旦操作 grantDeployAndCreateManager 命令,才開始限制用戶部署合約權限

ps:一開始權限基本開放,而不是像常規系統設計那樣,一開始權限為無,等到分配好權限才可以相應的的操作。

2、底層默認是寫表操作,寫表操作就有了CRUD等操作,常規的區塊鏈體系是在不斷區塊打包過程中附加數據,Fisco Bcos 提供寫表操作,實質上業務數據可以有修改的權限,

所以在鏈搭建好後,就必須限制Update等操作權限,並且在業務設計時候,需要多方去驗證修改數據等過程,才可以防止區塊鏈底層數據讓高權限的人的篡改。

ps:與官方人員交談,提供的例子

比如官方給出的存證的例子,一個證據X,需要A,B機構確認。先是證據X上鏈(一筆交易),然後機構A看到證據,
確認有效(又一筆交易),機構B演的證據,確認有效(又一筆交易)。三筆交易完成業務共識的邏輯。
別人取證X的時候,讀區塊鏈,查看是否A,B都確認過,確認過了,證據X才有效。

 

四、場景構想搭建

 

我們在底層完成各種系統化的搭建,現在要使用多種方式進行權限管控,以及數據上鏈等操作。

1、我們首先要建立鏈管理員、系統管理員、普通用戶。

2、其次我們要使用控制台 或sdk進行管理員等設定。

3、對合約的部署權限、以及數據權限更新操作做授權。

4、在sdk 中配置授權用戶的pem、p12密鑰的使用。

5、使用合約操作,進行合約部署,合約CRUD操作。

6、使用CRUDService 進行數據操作。

7、使用PermissionService 進行權限控制。

最後根據我們設定好的權限,完成多個不同身份用戶進行的數據操作,這樣我們就完成生產環境下的數據上鏈操作。

 

備註:以下操作,可以參考web3sdk單元測試。官方github web3sdk 地址:https://github.com/FISCO-BCOS/web3sdk

 

五、實操演練

 

(一)創建和管理用戶

創建用戶,用於後續的管理員設置,進行權限管理設置。

官方資料:https://fisco-bcos-documentation.readthedocs.io/zh_CN/latest/docs/tutorial/account.html

fisco bcos 底層 支持控制台創建賬戶、sdk 創建賬戶

 

先採用控制台進行基礎用戶創建,以及基本全是設置

在console 目錄下 使用bash get_account.sh、bash get_account.sh -p 創建不同的賬戶    Usage: ./get_account.sh    default generate account and store private key in PEM format file(默認生成pem格式用戶)  -p generate account and store private key in PKCS12 format file(默認生成p12格式用戶)  -k [FILE] calculate address of PEM format [FILE](通過pem 私鑰文件生成賬戶地址)  -P [FILE] calculate address of PKCS12 format [FILE](通過p12 私鑰文件生成賬戶地址)  -h Help

 

創建鏈管理員 ,pem 格式

ubuntu@VM-16-14-ubuntu:~/generator/console$ bash get_account.sh  [INFO] Account Address : 0x83a37766067ea59eea78135b20a4afc251246e88  [INFO] Private Key (pem) : accounts/0x83a37766067ea59eea78135b20a4afc251246e88.pem

 

創建三個用戶

1、具有 發佈合約權限的用戶

ubuntu@VM-16-14-ubuntu:~/generator/console$ bash get_account.sh -p  Enter Export Password:123456  Verifying - Enter Export Password:123456  [INFO] Account Address : 0xb93bb9276d97f5f75ea574965beab99f72310e45  [INFO] Private Key (p12) : accounts/0xb93bb9276d97f5f75ea574965beab99f72310e45.p12

 

2、系統管理員

ubuntu@VM-16-14-ubuntu:~/generator/console$ bash get_account.sh -p  Enter Export Password:  Verifying - Enter Export Password:  [INFO] Account Address : 0xca96eb0e7c70c9117a2b5bda65cbcfc1b37a35c2  [INFO] Private Key (p12) : accounts/0xca96eb0e7c70c9117a2b5bda65cbcfc1b37a35c2.p12

 

3、普通用戶

ubuntu@VM-16-14-ubuntu:~/generator/console$ bash get_account.sh -p  Enter Export Password:  Verifying - Enter Export Password:  [INFO] Account Address : 0x190b5d0a7ed4754c9226ee96c50cd125ec5720bf  [INFO] Private Key (p12) : accounts/0x190b5d0a7ed4754c9226ee96c50cd125ec5720bf.p12

 

pem登錄方式:

bash ./start.sh 1 -pem accounts/0x83a37766067ea59eea78135b20a4afc251246e88.pem

 

p12 登錄方式:(需要輸入密碼)

bash ./start.sh 1 -p12 accounts/0xb93bb9276d97f5f75ea574965beab99f72310e45.p12

 

 

(二)控制台基本權限設置

設定賬戶1為鏈管理員賬戶,賬戶2為系統管理員賬戶,賬戶3為普通賬戶。

1、鏈管理員賬戶擁有權限管理的權限,即能分配權限。

[group:1]> grantDeployAndCreateManager 0x83a37766067ea59eea78135b20a4afc251246e88  {  "code":0,  "msg":"success"  }

2、系統管理員賬戶可以管理系統相關功能的權限,每一種系統功能權限都需要單獨分配,
具體包括部署合約和創建用戶表的權限、管理節點的權限、利用CNS部署合約的權限以及修改系統參數的權限。
鏈管理員賬戶可以授權其他賬戶為鏈管理員賬戶或系統管理員賬戶,

 

[group:1]> grantDeployAndCreateManager 0xb93bb9276d97f5f75ea574965beab99f72310e45  {  "code":0,  "msg":"success"  }     

 

3、也可以授權指定賬號可以寫指定的用戶表,即普通賬戶。

用某個用戶登錄後,使用命令賦予權限,前提是他擁有該權限操作

權限命令:https://fisco-bcos-documentation.readthedocs.io/zh_CN/release-2.0/docs/manual/permission_control.html

(三)Sdk下配置

1、將控制台生成account 目錄下的文件copy sdk中。

 

 

 applicationContext.xml 文件配置修改,其中包括密鑰文件的配置。

<?xml version="1.0" encoding="UTF-8"?>  <beans xmlns="http://www.springframework.org/schema/beans"         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"         xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">        <bean id="encryptType" class="org.fisco.bcos.web3j.crypto.EncryptType">          <constructor-arg value="0"/> <!-- 0:standard 1:guomi -->      </bean>        <bean id="groupChannelConnectionsConfig" class="org.fisco.bcos.channel.handler.GroupChannelConnectionsConfig">          <property name="allChannelConnections">              <list>  <!-- 每個群組需要配置一個bean,每個群組可以配置多個節點 -->                  <bean id="group1"  class="org.fisco.bcos.channel.handler.ChannelConnections">                      <property name="groupId" value="1" /> <!-- 群組的groupID -->                      <property name="connectionsStr">                          <list>                                <value>對應的節點ip:20201</value>                              <value>對接節點ip:20200</value>  <!-- IP:channel_port -->                            </list>                      </property>                  </bean>                  <bean id="group2"  class="org.fisco.bcos.channel.handler.ChannelConnections">                      <property name="groupId" value="2" /> <!-- 群組的groupID -->                      <property name="connectionsStr">                          <list>                              <value>127.0.0.1:20202</value>                              <value>127.0.0.1:20203</value>                          </list>                      </property>                  </bean>              </list>          </property>      </bean>  
<bean id="channelService" class="org.fisco.bcos.channel.client.Service" depends-on="groupChannelConnectionsConfig"> <property name="groupId" value="1" /> <!-- 配置連接群組1 --> <property name="agencyName" value="fisco" /> <!-- 配置機構名 --> <property name="allChannelConnections" ref="groupChannelConnectionsConfig"></property> </bean> <bean id="p12" class="org.fisco.bcos.channel.client.P12Manager" init-method="load" > <property name="password" value="123456" /> <property name="p12File" value="classpath:0xb93bb9276d97f5f75ea574965beab99f72310e45.p12" /> </bean> <bean id="pem" class="org.fisco.bcos.channel.client.PEMManager" init-method="load" > <property name="pemFile" value="classpath:0x83a37766067ea59eea78135b20a4afc251246e88.pem" /> </bean> </beans>

如果要寫單元測試

也要把相關配置copy 過去,詳情見圖

 

 (四)單元測試 合約部署,CRUD操作

1、基礎設置,包括具有部署合約權限用戶設置

  private Credentials credentials;      private static BigInteger gasPrice = new BigInteger("300000000");      private static BigInteger gasLimit = new BigInteger("300000000");      @Autowired      Web3j web3j;      protected String tempDirPath =  new File("src/main/resources/").getAbsolutePath();      //這很重要,沒有這個無法通過      @Before      public void setUp() throws Exception {          ApplicationContext context =                  new ClassPathXmlApplicationContext(                          "classpath:applicationContext-keystore-sample.xml");          // test p12          P12Manager p12 = context.getBean(P12Manager.class);          ECKeyPair p12KeyPair = p12.getECKeyPair();            System.out.println("p12KeyPair.getPrivateKey() = " + p12KeyPair.getPrivateKey().toString(16));          System.out.println("p12KeyPair.getPublicKey() = " + p12KeyPair.getPublicKey().toString(16));              ECPublicKey publicKey = (ECPublicKey) p12.getPublicKey();          byte[] publicKeyBytes = publicKey.getQ().getEncoded(false);          BigInteger publicKeyValue =                  new BigInteger(1, Arrays.copyOfRange(publicKeyBytes, 1, publicKeyBytes.length));            System.out.println("publicKeyValue = " + publicKeyValue.toString(16));            credentials = Credentials.create(p12KeyPair);//這裡將具有合約部署權限的用戶設置進去,當前操作對象            System.out.println("credentials  getAddress= " + credentials.getAddress());      }        @After      public void tearDown() {      }

2、部署合約

 @Test      //1、部署合約      public void DeployTable() throws Exception {          // 部署合約          TableTemp tableTemp = TableTemp.deploy(web3j, credentials, new StaticGasProvider(gasPrice, gasLimit)).send();            if (tableTemp != null) {              System.out.println("TableTemp address is: " + tableTemp.getContractAddress());          }        }

3、創建表合約操作,此時,需要用到部署合約時候生成的地址

 //2、創建表操作      @Test      public void CreateTableTest()throws Exception  {          String contractAddress = "0xb4245b7b6cc33f8f65d8bf37f084dec3e31ca573";//合約部署時候的生成的地址          // 加載合約地址          TableTemp tableTemp = TableTemp.load(contractAddress, web3j, credentials, new StaticGasProvider(gasPrice, gasLimit));          TransactionReceipt receipt = tableTemp.create().send();          System.out.println("AssetTest.AssetTransfer receipt="+receipt.toString());      }

 

4、插入表操作(合約地址改為自己測試的,筆者由於多次單元測試,合約地址不同)

 

 //3.1、插入表操作 無返回值操作      @Test      public void InsertTableTest()throws Exception  {          String contractAddress = "0x215ac9f7af5766ff45d80082091856b54fcf4308";          // 加載合約地址          TableTemp tableTemp = TableTemp.load(contractAddress, web3j, credentials, new StaticGasProvider(gasPrice, gasLimit));            String name = "wq";          int item_id = Integer.parseInt("2");          String item_name ="aaa";          String item_address ="ddd";          tableTemp.insert(name, BigInteger.valueOf(item_id), item_name,item_address).send();              }        //3.2、插入表操作      @Test      public void InsertTableByReturnTest()throws Exception  {          String contractAddress = "0xb4245b7b6cc33f8f65d8bf37f084dec3e31ca573";          // 加載合約地址          TableTemp tableTemp = TableTemp.load(contractAddress, web3j, credentials, new StaticGasProvider(gasPrice, gasLimit));            String name = "ak";          int item_id = Integer.parseInt("1");          String item_name ="tempUser";          String item_address ="北京";              TransactionReceipt send = tableTemp.insert(name, BigInteger.valueOf(item_id), item_name, item_address).send();          System.out.println(" send= "+send.toString());             }

 

5、刪除表操作

 //4.1刪除表數據操作      @Test      public void DeleteTableTest()throws Exception  {          String contractAddress = "0x215ac9f7af5766ff45d80082091856b54fcf4308";          // 加載合約地址          TableTemp tableTemp = TableTemp.load(contractAddress, web3j, credentials, new StaticGasProvider(gasPrice, gasLimit));          TransactionReceipt send=  tableTemp.remove("ak",BigInteger.valueOf(1)).send();            System.out.println("send.toString() = " + send.toString());          System.out.println("send.getContractAddress() = " + send.getContractAddress());          System.out.println("send.getBlockHash() = " + send.getBlockHash());          System.out.println("send.getBlockNumber() = " + send.getBlockNumber());        }      //4.2刪除表數據操作      @Test      public void DeleteTableByReturnTest()throws Exception  {          String contractAddress = "0xb4245b7b6cc33f8f65d8bf37f084dec3e31ca573";          // 加載合約地址          TableTemp tableTemp = TableTemp.load(contractAddress, web3j, credentials, new StaticGasProvider(gasPrice, gasLimit));            int item_id = Integer.parseInt("1");          String name="ak";          RemoteCall<TransactionReceipt> remove =                  (RemoteCall<TransactionReceipt>) tableTemp.remove(name,BigInteger.valueOf(item_id));            TransactionReceipt transactionReceipt = remove.send();          List<TableTemp.RemoveResultEventResponse> removeResultEvents =                  tableTemp.getRemoveResultEvents(transactionReceipt);          if (removeResultEvents.size() > 0) {              TableTemp.RemoveResultEventResponse reomveResultEventResponse = removeResultEvents.get(0);              System.out.println(                      "removeCount = " + reomveResultEventResponse.count.intValue());          } else {              System.out.println("tableTemp table does not exist.");          }          }

6、查詢表操作,由於合約返回字段有限,最好不要超過三個,有可能會報錯。如果使用返回strust是可以解決該問題的。

開頭加上這個:pragma experimental ABIEncoderV2;
返回值可以用struct

 

  //5、表查詢      @Test      public void SelectTableTest() throws  Exception{          String contractAddress = "0xa94c07af700bf2e435a3051b0a98f2f75eca0298";          // 加載合約地址          TableTemp tableTemp = TableTemp.load(contractAddress, web3j, credentials, new StaticGasProvider(gasPrice, gasLimit));          Tuple3<List<byte[]>, List<BigInteger>, List<byte[]>> lists = tableTemp.select("ak").send();          //這個只是返回合約執行的結果,不會返回本身數據庫表數據       //   System.out.println("send.toString() = " + send.toString());          List<byte[]> value1 = lists.getValue1();          List<BigInteger> value2 = lists.getValue2();          List<byte[]> value3 = lists.getValue3();            for (int i = 0; i < value1.size(); i++) {              String name = new String(value1.get(i));                System.out.println("name = " + name);              int item_id = value2.get(i).intValue();                System.out.println("item_id = " + item_id);              String item_name = new String(value3.get(i));                System.out.println("item_name = " + item_name);          }        }

7、更新表操作,當前筆者還沒設置更新操作權限,所以該方法是可以修改表數據

//6、表更新      @Test      public void UpateTableTest() throws  Exception{          String contractAddress = "0xb940c1966a6ce94484f0fdabd3bb8cb38edc9dfd";          // 加載合約地址          TableTemp tableTemp = TableTemp.load(contractAddress, web3j, credentials, new StaticGasProvider(gasPrice, gasLimit));          TransactionReceipt ak=  tableTemp.update("ak",BigInteger.valueOf(1),"121","wew").send();          System.out.println("ak.toString() = " + ak.toString());      }

 

ps:由於合約操作在實際中返回值等問題,可能存在許多不確定等坑,所以和官方聊之後,可以使用crudService進行表的操作。

 

(五) 採用CrudService 進行表數據操作

CrudService 本身就是對錶的操作的服務封裝。

這裡的單元測試需要用到 基礎設置TestBase,主要配置具有表操作權限的用戶。

package customTest;    import java.math.BigInteger;  import java.util.Arrays;    import org.bouncycastle.jce.interfaces.ECPublicKey;  import org.fisco.bcos.channel.client.P12Manager;  import org.fisco.bcos.channel.client.Service;  import org.fisco.bcos.web3j.crypto.Credentials;  import org.fisco.bcos.web3j.crypto.ECKeyPair;  import org.fisco.bcos.web3j.protocol.Web3j;  import org.fisco.bcos.web3j.protocol.channel.ChannelEthereumService;  import org.fisco.bcos.web3j.tx.gas.StaticGasProvider;  import org.junit.AfterClass;  import org.junit.BeforeClass;  import org.springframework.context.ApplicationContext;  import org.springframework.context.support.ClassPathXmlApplicationContext;    public class TestBase {    public static ApplicationContext context = null;    public static Credentials credentials;      protected static Web3j web3j;    protected static BigInteger gasPrice = new BigInteger("30000000");    protected static BigInteger gasLimit = new BigInteger("30000000");    protected static String address;    protected static BigInteger blockNumber;    protected static String blockHash;    protected static String txHash;      @BeforeClass    public static void setUpBeforeClass() throws Exception {          context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");        Service service = context.getBean(Service.class);      service.run();        ChannelEthereumService channelEthereumService = new ChannelEthereumService();      channelEthereumService.setChannelService(service);        web3j = Web3j.build(channelEthereumService, service.getGroupId());        ApplicationContext context =              new ClassPathXmlApplicationContext(                      "classpath:applicationContext-keystore-sample.xml");      // test p12      P12Manager p12 = context.getBean(P12Manager.class);      ECKeyPair p12KeyPair = p12.getECKeyPair();        System.out.println("p12KeyPair.getPrivateKey() = " + p12KeyPair.getPrivateKey().toString(16));      System.out.println("p12KeyPair.getPublicKey() = " + p12KeyPair.getPublicKey().toString(16));          ECPublicKey publicKey = (ECPublicKey) p12.getPublicKey();      byte[] publicKeyBytes = publicKey.getQ().getEncoded(false);      BigInteger publicKeyValue =              new BigInteger(1, Arrays.copyOfRange(publicKeyBytes, 1, publicKeyBytes.length));        System.out.println("publicKeyValue = " + publicKeyValue.toString(16));        credentials = Credentials.create(p12KeyPair);        System.out.println("credentials  getAddress= " + credentials.getAddress());    }      @AfterClass    public static void setUpAfterClass() throws Exception {      ((ClassPathXmlApplicationContext) context).destroy();    }  }

 

以下是crudservice 的單元測試全過程操作,依法操作就可以了,關鍵地方已經有了注釋。

package customTest;    import org.bouncycastle.jce.interfaces.ECPublicKey;  import org.fisco.bcos.Application;  import org.fisco.bcos.channel.client.P12Manager;  import org.fisco.bcos.temp.TableTemp;  import org.fisco.bcos.web3j.crypto.Credentials;  import org.fisco.bcos.web3j.crypto.ECKeyPair;  import org.fisco.bcos.web3j.precompile.crud.CRUDService;  import org.fisco.bcos.web3j.precompile.crud.Condition;  import org.fisco.bcos.web3j.precompile.crud.Entry;  import org.fisco.bcos.web3j.precompile.crud.Table;  import org.fisco.bcos.web3j.protocol.Web3j;  import org.fisco.bcos.web3j.tx.gas.StaticGasProvider;  import org.junit.After;  import org.junit.Assert;  import org.junit.Before;  import org.junit.Test;  import org.junit.runner.RunWith;  import org.springframework.beans.factory.annotation.Autowired;  import org.springframework.boot.test.context.SpringBootTest;  import org.springframework.context.ApplicationContext;  import org.springframework.context.support.ClassPathXmlApplicationContext;  import org.springframework.test.context.junit4.SpringRunner;  import java.io.File;  import java.math.BigInteger;  import java.util.Arrays;  import java.util.List;  import java.util.Map;  import java.util.Random;  import static org.junit.jupiter.api.Assertions.assertEquals;      /*  * 1、繼承 TestBase,配置文件在main的java的resources中applicationContext.xml  * */  @RunWith(SpringRunner.class)  @SpringBootTest(classes = Application.class)  public class CRUDServiceTest extends TestBase{      //這裡如果設置了權限,那麼必須權限用戶才可以使用,請看TestBase 中的改造,credentials      private CRUDService crudSerivce = new CRUDService(web3j, credentials);        @SuppressWarnings("unchecked")      @Test      public void CreateTest() throws Exception {            String tableName = "t_item2";          String key = "name";          String valueFields  = "item_id, item_name,item_address,item_count";          Table table = new Table(tableName, key, valueFields);            // create table          int resultCreate = crudSerivce.createTable(table);          Assert.assertEquals(resultCreate, 0);          }      @SuppressWarnings("unchecked")      @Test      public  void Insert()throws Exception{            String tableName = "t_item2";          String key = "name";            Table table = new Table(tableName, key);          int insertResult = 0;          int num = 5;          for(int i = 1; i <= num; i++)          {              Entry insertEntry = table.getEntry();              insertEntry.put("item_id", "q");              insertEntry.put("item_name", "q"+i);              insertEntry.put("item_address", "q"+i);              insertEntry.put( "item_count",BigInteger.valueOf(i).toString());              table.setKey("q");              insertResult += crudSerivce.insert(table, insertEntry);          }          Assert.assertEquals(insertResult, num);        }      @SuppressWarnings("unchecked")      @Test      public  void  Select()throws Exception{          String tableName = "t_item2";          String key = "name";          Table table = new Table(tableName, key);          // select records          Condition condition1 = table.getCondition();          condition1.EQ("name", "q");          condition1.EQ("item_id", "q");         // condition1.Limit(1);          table.setKey("q");//查詢記錄sql語句必須在where子句中提供表的主鍵字段值。            List<Map<String, String>> resultSelect1 = crudSerivce.select(table, condition1);          Assert.assertEquals(resultSelect1.get(0).get("name"), "q");          Assert.assertEquals(resultSelect1.get(0).get("item_id"), "q");          Assert.assertEquals(resultSelect1.get(0).get("item_name"), "q1");      }      @SuppressWarnings("unchecked")      @Test      public void Update() throws Exception{          String tableName = "t_item2";          String key = "name";          Table table = new Table(tableName, key);          int num = 5;          table.setKey("q");//查詢記錄sql語句必須在where子句中提供表的主鍵字段值。          Entry updateEntry = table.getEntry();          updateEntry.put("item_id", "徐徐吹v下次v");          updateEntry.put("item_name", "121212");          Condition updateCondition = table.getCondition();          updateCondition.EQ("name", "q");          updateCondition.EQ("item_id", "aaaaa");          int updateResult = crudSerivce.update(table, updateEntry, updateCondition);          Assert.assertEquals(updateResult, num);      }  }

 

ps:上述操作除了創建表有權限用戶需要操作,其他的操作任意用戶均可以操作。

(六)進行權限操作

 

本例子,就是通過第一次創建表操作,無授權和有授權等模式多次測試,從而進行驗證當我們設置表更新權限後,沒有表更新權限的用戶是無法進行更新表操作的,賦予這個用戶更新表操作的權限後,就可以進行表更新操作。

package customTest;    import org.fisco.bcos.channel.client.PEMManager;  import org.fisco.bcos.temp.TableTemp;  import org.fisco.bcos.web3j.crypto.Credentials;  import org.fisco.bcos.web3j.crypto.ECKeyPair;  import org.fisco.bcos.web3j.precompile.crud.CRUDService;  import org.fisco.bcos.web3j.precompile.crud.Condition;  import org.fisco.bcos.web3j.precompile.crud.Entry;  import org.fisco.bcos.web3j.precompile.crud.Table;  import org.fisco.bcos.web3j.precompile.permission.PermissionService;  import org.fisco.bcos.web3j.tx.gas.StaticGasProvider;  import org.junit.Assert;  import org.junit.Test;    import static org.junit.Assert.assertEquals;    public class PermissionTest extends TestBase {            @Test      // 授權新創建用戶的權限,測試它部署合約的權限,正常不授權無法部署      public void PermissionDeploy() throws Exception {            //1、初始化創建一個用戶,沒有在底層註冊過的          String tempAddress="0x80e3c3f1f1140fbc550fbfdaa318073af373141d";          String tempPriKey="9265efb6b860ef244f4fbe3dd445f7829e86d11226573190c026323f77ebcd22";          String tempPublicKey="1f9c09a4df7e336961c06e1f2373fb2ef6a1b642c444652a7a5a84b04bdc668431bbddab4a1665cb382d6a94aee9ff18bf88210bae7a2388315b2bc5253bcaa";              //pem  鏈管理員進行操作,對新用戶進行合約部署權限授權          PEMManager pem = context.getBean(PEMManager.class);          ECKeyPair pemKeyPair = pem.getECKeyPair();            //1、鏈管理員操作 授權新用戶的可以發佈和部署合約          credentials = Credentials.create(pemKeyPair);           PermissionService permissionService = new PermissionService(web3j, credentials);          String s = permissionService.grantDeployAndCreateManager(tempAddress);          System.out.println("s = " + s);//這個是授權狀態            //2、使用新用戶新合約部署測試          Credentials userCredentials=Credentials.create(tempPriKey,tempPublicKey);          // 部署合約          TableTemp tableTemp = TableTemp.deploy(web3j, userCredentials, new StaticGasProvider(gasPrice, gasLimit)).send();            if (tableTemp != null) {              System.out.println("TableTemp address is: " + tableTemp.getContractAddress());          }        }      @Test      // 授權新創建用戶的權限,用戶表操作修改權限      public void PermissionGrantUserTable() throws Exception {            //1、初始化創建一個用戶,沒有在底層註冊過的          String tempAddress="0x80e3c3f1f1140fbc550fbfdaa318073af373141d";          String tempPriKey="9265efb6b860ef244f4fbe3dd445f7829e86d11226573190c026323f77ebcd22";          String tempPublicKey="1f9c09a4df7e336961c06e1f2373fb2ef6a1b642c444652a7a5a84b04bdc668431bbddab4a1665cb382d6a94aee9ff18bf88210bae7a2388315b2bc5253bcaa";              //pem  鏈管理員進行操作,對新用戶進行合約部署權限授權          PEMManager pem = context.getBean(PEMManager.class);          ECKeyPair pemKeyPair = pem.getECKeyPair();            //1、鏈管理員操作 授權新用戶的可以發佈和部署合約          credentials = Credentials.create(pemKeyPair);          PermissionService permissionService = new PermissionService(web3j, credentials);          String s = permissionService.grantUserTableManager("t_item2",tempAddress);          System.out.println("s = " + s);//這個是授權狀態            //2、使用新用戶進行表更新 操作          Credentials userCredentials=Credentials.create(tempPriKey,tempPublicKey);           //完成後,測試表操作中update操作看看是否可以成功          CRUDService crudSerivce = new CRUDService(web3j, userCredentials);          String tableName = "t_item2";          String key = "name";          Table table = new Table(tableName, key);          int num = 5;          table.setKey("q");//查詢記錄sql語句必須在where子句中提供表的主鍵字段值。          Entry updateEntry = table.getEntry();          updateEntry.put("item_id", "徐徐吹v下次v");          updateEntry.put("item_name", "121212");          Condition updateCondition = table.getCondition();          updateCondition.EQ("name", "q");          updateCondition.EQ("item_id", "aaaaa");          int updateResult = crudSerivce.update(table, updateEntry, updateCondition);          Assert.assertEquals(updateResult, num);            //結果測試成功,使用授權用戶操作的表,可以進行更新操作;否則,不具備這個權限的用戶,是無法操作的      }    }

 

六、總結

根據本篇教程,可以完成底層權限設置、以及sdk實際權限控制操作、最後實現數據上鏈等等。讀者可以根據自己的業務需求修改表結構,依照上述流程可以在生產環境中大致進行業務開發。

系列教程到此,暫時告一段落,基本從頭到尾可以按照每一章節對Fisco Bcos 流程從頭到尾進行一次模擬生產環境的實踐。