使用细粒度访问控制库的示例 Walkthough

本主题提供了有关如何使用该库和链代码的一些示例。这些都假定已调用 Init() 来创建引导实体,Init()invoke() 的调用者为 "%CN%frank.thomas@example.com"。应用程序中的正常流将创建一些初始访问控制列表,这些列表将用于授予或拒绝对其他实体的访问。

初始化

在实例化链代码时调用 Initialization() 创建引导实体。例如:

import "chaincodeACL"
func (t \*SimpleChaincode) Init(nil, stub shim.ChaincodeStubInterface) pb.Response
{
         err := chaincodeACL.Initialization(stub)
}

创建新的 ACL

import "chaincodeACL"
...
{

**ACLMgr**  := chaincodeACL.NewACLManager(nil, stub) // Not specify identity, use caller's identity as default.

// Define a new ACL
**newACL**  := chaincodeACL.ACL{

    "AllowAdmins",   // ACL name
    "Allow admins full access",  // Description
    []string{"CREATE","READ","UPDATE","DELETE"},    // Accesses allowed or not
    true, // Allowed
    []string{"%CN%bob.dole@example.com","%OU%example.com,"%GRP%admins"}, // Initial identity patterns
    ".ACLs.acl", // Start with bootstrap ACL

}

// Add this ACL with default identity (caller's identify here)
err :=  **ACLMgr**.Create( **newACL** , nil)

}

现在我们有了新的 ACL,我们可以用它来修改谁可以执行某些操作。因此,我们将首先将此新 ACL 添加到引导组 .Groups 中,以允许任何管理员创建组。

将 ACL 添加到组

import "chaincodeACL"
…
{

  **groupMgr**  := chaincodeACL.NewGroupManager(nil, stub) // Not specify identity, use caller's identity as default.
  err :=  **groupMgr**.AddAfterACL(

    ".Groups",     // Bootstrap group name
    ".Groups.ACL", // Which ACL to add after
    "AllowAdmins", // The new ACL to add
    nil            // with default identity that's frank.thomas

)

}

这会将 AllowAdmins ACL 添加到初始引导 ACL 之后的引导组 .Groups 中。因此,这可以确保 Frank Thomas 仍然可以对 .Groups 执行操作,因为授予他权限的 ACL 在列表中处于第一位。但是,现在与 AllowAdmins ACL 匹配的任何人都可以执行 CREATE、READ、UPDATE 或 DELETE 操作(他们现在可以创建新组)。

创建新组

管理员现在可以创建新组:

import "chaincodeACL"
...
{

...
  // Define a new group.
  **newGroup**  := chaincodeACL.Group{

      "AdminGrp",   // Name of the group
      "Administrators of the app",   // Description of the group
      {"%CN%jill.muller@example.com","%CN%ivan.novak@example.com","%ATTR%role=admin"},
      []string{"AllowAdmins"},   // The ACL for the group

    }

  **groupMgr**  := chaincodeACL.NewGroupManager(nil, stub)   // Not specify identity, use caller's identity as default.
  err :=  **groupMgr**.Create( **newGroup** , bob\_garcia\_certificate)   // Using a specific certificate

...
}

此调用使用显式身份 - Bob Garcia(使用他的证书)的身份 - 尝试创建一个新组。由于 Bob Garcia 匹配 AllowAdmins ACL 中的模式,并且该 ACL 的成员可以在引导组 .Groups 上执行 CREATE 操作,因此此调用将成功。如果吉姆·席尔瓦 (Jim Silva) 不在组织单元 example.com 或组 AdminGrp(该组仍然不存在)中,他的证书作为最后一个参数传递,则调用将失败,因为他没有相应的权限。此调用将创建一个名为 "AdminGrp" 的新组,该组的初始成员为 jill.muller@example.com 和 ivan.novak@example.com,或者具有属性 (ABAC) role=admin 的任何成员。

创建新的资源

import "chaincodeACL"
...
{

  ...
  **newResource**  :=  **chaincodeACL**.Resource{

      "transferMarble", // Name of resource to create

      "The transferMarble chaincode function", // Description of the resource

      []string{"AllowAdmins"}, // Single ACL for now allowing admins

  }

  **resourceMgr**  :=  **chaincodeACL**.NewResourceManager(nil, stub)  // Not specify identity, use caller's identity as default.
  err :=  **resourceMgr**.Create(resourceMgr, nil)   // Using caller's certificate

  ...
}

这将创建一个名为 transferMarble 的新资源,应用程序可以使用该资源来控制对 transferMarble 链代码函数的访问。访问权限当前受 AllowAdmins 访问控制列表的限制。

检查资源的访问权限

我们可以在链代码中使用这个新资源,只允许管理员通过修改大理石链代码的 invoke() 方法来传输大理石,如下所示:

import "chaincodeACL"
…
func (t \*SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response {

  **resourceMgr**  :=  **chaincodeACL**.NewResourceManager(nil, stub)   // Not specify identity, use caller's identity as default.

  function, args := stub.GetFunctionAndParameters()

  fmt.Println("invoke is running " + function)        // Handle different functions

  if function == "initMarble" {   //create a new marble

      return t.initMarble(stub, args)}

  else if function == " **transferMarble**" { //change owner of a specific marble

    **allowed** , err : =  **resourceMgr**. **CheckAccess** ("transferMarble", "UPDATE", nil)
    if  **allowed**  == true {

      return t.transferMarble(stub, args)

    else {

      return NOACCESS

    }

    } else if function == "transferMarblesBasedOnColor" { //transfer all marbles of a certain color
    …

    }

}