在Fabric链码开发过程中,有时候需要获取调用链码的用户信息,比如在一个数据共享的链码中,需要根据用户的信息对数据进行限制访问。幸运的是,Fabric提供了ChaincodeStubInterface接口,其中GetCreator方法可以获取提交请求的用户的相关信息。接口描述如下:
// GetCreator returns `SignatureHeader.Creator` (e.g. an identity)
// of the `SignedProposal`. This is the identity of the agent (or user)
// submitting the transaction.
GetCreator() ([]byte, error)
从GetCreator接口描述中可以看出,GetCreator方法返回的是一个byte数组,而将byte数组转换为string对应的是调用用户identity信息序列号的字符串,如下所示:
\n\007DEFAULT\022\272\006-----BEGIN CERTIFICATE-----\nMIICNjCCAd2gAwIBAgIRAMnf9/dmV9RvCCVw9pZQUfUwCgYIKoZIzj0EAwIwgYEx\nCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1TYW4g\nRnJhbmNpc2NvMRkwFwYDVQQKExBvcmcxLmV4YW1wbGUuY29tMQwwCgYDVQQLEwND\nT1AxHDAaBgNVBAMTE2NhLm9yZzEuZXhhbXBsZS5jb20wHhcNMTcxMTEyMTM0MTEx\nWhcNMjcxMTEwMTM0MTExWjBpMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZv\ncm5pYTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzEMMAoGA1UECxMDQ09QMR8wHQYD\nVQQDExZwZWVyMC5vcmcxLmV4YW1wbGUuY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0D\nAQcDQgAEZ8S4V71OBJpyMIVZdwYdFXAckItrpvSrCf0HQg40WW9XSoOOO76I+Umf\nEkmTlIJXP7/AyRRSRU38oI8Ivtu4M6NNMEswDgYDVR0PAQH/BAQDAgeAMAwGA1Ud\nEwEB/wQCMAAwKwYDVR0jBCQwIoAginORIhnPEFZUhXm6eWBkm7K7Zc8R4/z7LW4H\nossDlCswCgYIKoZIzj0EAwIDRwAwRAIgVikIUZzgfuFsGLQHWJUVJCU7pDaETkaz\nPzFgsCiLxUACICgzJYlW7nvZxP7b6tbeu3t8mrhMXQs956mD4+BoKuNI\n-----END CERTIFICATE-----\n
可以看出返回的信息里包含MSPID和用户证书两部分内容,那么如何将MSPID和用户证书分别取取出来哪?可以按照以下步骤。
通过调用shim.ChaincodeStubInterface接口中的GetCreator接口,实际上返回的是github.com/hyperledger/fabric/protos/msp包中SerializedIdentity对象序列号的字符串,因此,我们只需将查询到的字符串转换回去就可以了。示例代码如下:
creatorByte, err := stub.GetCreator()
// 构造SerializedIdentity方法,并将creator进行Unmarshal
si := &msp.SerializedIdentity{}
err = proto.Unmarshal(creatorByte, si)
if err != nil {
return "", err
}
fmt.Println("MSPID: " + si.GetMspid())
fmt.Println("Cert: " + string(si.GetIdBytes()))
通过测试,返回的信息如下:
MSPID: DEFAULT
Cert: -----BEGIN CERTIFICATE-----
MIICNjCCAd2gAwIBAgIRAMnf9/dmV9RvCCVw9pZQUfUwCgYIKoZIzj0EAwIwgYEx
CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1TYW4g
RnJhbmNpc2NvMRkwFwYDVQQKExBvcmcxLmV4YW1wbGUuY29tMQwwCgYDVQQLEwND
T1AxHDAaBgNVBAMTE2NhLm9yZzEuZXhhbXBsZS5jb20wHhcNMTcxMTEyMTM0MTEx
WhcNMjcxMTEwMTM0MTExWjBpMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZv
cm5pYTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzEMMAoGA1UECxMDQ09QMR8wHQYD
VQQDExZwZWVyMC5vcmcxLmV4YW1wbGUuY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0D
AQcDQgAEZ8S4V71OBJpyMIVZdwYdFXAckItrpvSrCf0HQg40WW9XSoOOO76I+Umf
EkmTlIJXP7/AyRRSRU38oI8Ivtu4M6NNMEswDgYDVR0PAQH/BAQDAgeAMAwGA1Ud
EwEB/wQCMAAwKwYDVR0jBCQwIoAginORIhnPEFZUhXm6eWBkm7K7Zc8R4/z7LW4H
ossDlCswCgYIKoZIzj0EAwIDRwAwRAIgVikIUZzgfuFsGLQHWJUVJCU7pDaETkaz
PzFgsCiLxUACICgzJYlW7nvZxP7b6tbeu3t8mrhMXQs956mD4+BoKuNI
-----END CERTIFICATE-----
上述的示例代码里面需要依赖github.com/golang/protobuf/proto 包和github.com/hyperledger/fabric/protos/msp 包,而这两个包在ccenv容器并没有打包进去。对于不能访问互联网的环境,install合约的时,会报找不到包的错误,如下所示:
testchaincode.go:8:2: cannot find package "github.com/golang/protobuf/proto" in any of:
/opt/go/src/github.com/golang/protobuf/proto (from $GOROOT)
/opt/gopath/src/github.com/golang/protobuf/proto (from $GOPATH)
在这里,我们使用govendor工具将这两个包导入chaincode代码。
首先,进入chaincode项目目录,进行初始化,生成vendor目录和vendor/verdor.json文件。
govendor init
然后,使用govendor fetch获取依赖包
govendor fetch github.com/golang/protobuf/proto
govendor fetch github.com/hyperledger/fabric/protos/[email protected]
这样,就把相关的包导入了vendor目录,其中msp包的版本最好设置为和fabric版本一致。此时,将整个项目目录发送到chaincode对应目录,就可以进行安装、实例和调用操作了。
vendor
├── github.com
│ ├── golang
│ │ └── protobuf
│ │ ├── LICENSE
│ │ └── proto
│ │ ├── clone.go
│ │ ├── decode.go
│ │ ├── deprecated.go
│ │ ├── discard.go
│ │ ├── encode.go
│ │ ├── equal.go
│ │ ├── extensions.go
│ │ ├── lib.go
│ │ ├── message_set.go
│ │ ├── pointer_reflect.go
│ │ ├── pointer_unsafe.go
│ │ ├── properties.go
│ │ ├── table_marshal.go
│ │ ├── table_merge.go
│ │ ├── table_unmarshal.go
│ │ ├── text.go
│ │ └── text_parser.go
│ └── hyperledger
│ └── fabric
│ ├── LICENSE
│ └── protos
│ └── msp
│ ├── identities.pb.go
│ ├── identities.proto
│ ├── msp_config.go
│ ├── msp_config.pb.go
│ ├── msp_config.proto
│ ├── msp_principal.go
│ ├── msp_principal.pb.go
│ └── msp_principal.proto
└── vendor.json
本文描述了fabric系统中如何在链码中获取调用者的身份信息,并将相关的依赖包倒入chaincode项目。在链码开发中,如果依赖了go语言的包,也可以通过这种方式,将依赖包导入链码工程。