<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                >[info] 本文作者:http://www.hmoore.net/@runningday > 文檔地址:http://www.hmoore.net/runningday/fabric **默認的 POST /registrar接口** 官方REST接口當中,有一個`POST /registrar`接口,對應的實現為 ~~~ // fabric/core/rest/rest_api.go func Register() ~~~ 實際上,這個接口的作用是login,而不是注冊新用戶,有必要自己寫一個接口,提供注冊新用戶的功能。 **REST接口路由** 所有的REST接口,都定義在`fabric/core/rest/rest_api.go`文件中,通過如下方式添加路由: ~~~ // fabric/core/rest/rest_api.go router.Post("/registrar", (*ServerOpenchainREST).Register) ~~~ 因此,可以仿照此,添加一個新的接口: ~~~ // fabric/core/rest/rest_api.go router.Post("/users", (*ServerOpenchainREST).CreateUser) ~~~ 即`POST /users`接口提供注冊功能 **RegisterUser核心接口** 由于membersrvc提供了CA相關的服務,查閱官方文檔[CA API](http://hyperledger-fabric.readthedocs.io/en/v0.6/API/MemberServicesAPI/),了解到ECAA提供了注冊用戶的核心接口: ~~~ /fabric/membersrvc/ca/ecaa.go func (ecaa *ECAA) RegisterUser(ctx context.Context, in *pb.RegisterUserReq) (*pb.Token, error) ~~~ **RegisterUserReq結構體介紹** 首先看請求參數`in *pb.RegisterUserReq`: ~~~ // ca.pb.go type RegisterUserReq struct { Id *Identity Role Role Attributes []*Attribute Affiliation string Registrar *Registrar Sig *Signature } ~~~ * Id:即新用戶的enrollID,由注冊時用戶提供 * Role:新用戶的類型,分為幾個限定類型,按位掩碼規則 * Attributes:額外屬性 * Affiliation:新用戶所屬機構,也是幾個限定值,必須是`AffiliationGroups`數據庫表中已存在的值 * Registrar:本身也是一個結構體: ~~~ // ca.pb.go type Registrar struct { Id *Identity Roles []string DelegateRoles []string } ~~~ 它定義了為新用戶A提供注冊代理的注冊者B,這個有必要說一下,在fabric中,注冊用戶不是用戶A向系統發出單純注冊請求即可,而是在請求中需要包含注冊者B信息,有點類似于網站的強制邀請注冊。注冊者B必須有注冊該類型用戶A的權限,否則系統會拒絕這次請求,并提示: ~~~ member <registrar> is not a registrar ~~~ 其中Registrar.Roles定義了新用戶A,以后可注冊哪幾個類型新用戶;而Registrar.DelegateRoles則存儲了以后可以升級為Registrar.Roles的值,換句話說,就是該用戶A注冊的新用戶C,以后可注冊哪幾個類型新用戶。例如: ~~~ userReq := RegisterUserReq{ Id: Identity{Id: "Jim"}, Role: Role(1), Affiliation: "institution_a", Registrar: Registrar{ Id: Identity{Id: "admin"}, Roles: ["client", "peer", "validator"], DelegateRoles: ["client"], }, Sig: nil, } ~~~ 這個是注冊新用戶“Jim”的請求,enrollID(即用戶名)為“Jim”;用戶類型為1,即“client”;機構隸屬為“institution_a”;Attributes留空;注冊者是"admin",它是membersrvc默認的管理員賬戶,擁有注冊各種類型用戶的權限,其定義在membersrvc.yaml文件中, >[warning] 需要說明一點的就是:admin雖然在配置文件中已定義了很高的權限,但是在注冊新用戶之前,首先需要把admin用戶enroll到系統中,為的是將admin證書寫入到數據庫Certificates表中,這個操作一次即可。 繼續余下的字段,Jim若注冊成功,他將可以作為["client", "peer", "validator"]這3種角色的注冊者;但是由Jim注冊的新成員,最多只能作為["client"]的注冊者。 * Sig:上例中Sig留空,這個字段存儲了userReq請求的簽名,一個請求在發送之前,必須要通過注冊者私鑰進行簽名,如果留空則后續處理會報空指針錯誤;如果簽名錯誤,系統也會提示: ~~~ Signature verification failed. ~~~ **給請求簽名** 注冊前的最后一步就是給注冊請求簽名了,即給userReq.Sig賦予正確的值,簽名的私鑰用的是注冊者的enrollmentKey(或者叫做privateKey),可以通過讀取文件`viper.GetString("peer.fileSystemPath") + "/crypto/client/admin/ks/raw/enrollment.key"`得到raw數據,然后使用`primitives.PEMtoPrivateKey(raw, adminEnrollPwd)`解密得到enrollmentKey: ~~~ var path = viper.GetString("peer.fileSystemPath") + "/crypto/client/admin/ks/raw/enrollment.key" raw, err := ioutil.ReadFile(path) if err != nil { fmt.Println("failed loading registrar private key: " + err.Error()) return nil, err } privateKey, err := primitives.PEMtoPrivateKey(raw, []byte("Xurw3yU9zI0l")) if err != nil { fmt.Println("failed parsing private key: " + err.Error()) return nil, err } var registrarPrivateKey = privateKey.(*ecdsa.PrivateKey) ~~~ 但這并不是一個好的方法,最好能找到已經封裝好的接口,通過查看`fabric/core/crypto/node_impl.go`源碼,可以看到在`nodeImpl`結構體中,包含privateKey字段: ~~~ // fabric/core/crypto/node_impl.go type nodeImpl struct { enrollPrivKey *ecdsa.PrivateKey } ~~~ 但這個字段并沒有暴露出來,所以還需要找找別的方式。 后來在`fabric/core/crypto/crypto.go`文件中發現: ~~~ // fabric/core/crypto/crypto.go type CertificateHandler interface { // Sign signs msg using the signing key corresponding to the certificate Sign(msg []byte) ([]byte, error) } ~~~ 這里介紹說使用和證書對應的簽名秘鑰,對數據進行簽名,因為只有私鑰才會用于簽名,而公鑰常常用來加密,所以這個應該正是我所需要的,再看Sign()的實現: ~~~ // fabric/core/crypto/client_ecert_handler.go // Sign signs msg using the signing key corresponding to this ECert func (handler *eCertHandlerImpl) Sign(msg []byte) ([]byte, error) { return handler.client.signWithEnrollmentKey(msg) } // fabric/core/crypto/node_sign.go func (node *nodeImpl) signWithEnrollmentKey(msg []byte) ([]byte, error) { return primitives.ECDSASign(node.enrollPrivKey, msg) } ~~~ 這里赫然寫著node.enrollPrivKey,正是私鑰。所以使用CertificateHandler接口中的Sign()方法,是一個更好的途徑。 余下的流程就簡單了: ~~~ // sign the registration request with Registrar's private key // 獲取"admin"注冊者客戶端實例 adminClient, err := crypto.InitClient("admin", nil) // 獲取客戶端的CertificateHandler接口 handler, err := adminClient.GetEnrollmentCertificateHandler() // 將請求數據序列化為[]byte raw, _ := proto.Marshal(registerUserReq) // 使用admin的私鑰對請求簽名 result, err := handler.Sign(raw) // 簽名結果是序列化處理的[]byte,需要將其反序列化,以構建RegisterUserReq.Sig結構體 var ecdsaSignature = new(primitives.ECDSASignature) asn1.Unmarshal(result, ecdsaSignature) R, _ := ecdsaSignature.R.MarshalText() S, _ := ecdsaSignature.S.MarshalText() registerUserReq.Sig = &pbb.Signature{Type: pbb.CryptoType_ECDSA, R: R, S: S} ~~~ **發送注冊請求** 注冊者指定完成并已經enroll進CA系統中,請求已被正確簽名,這時就可以發送注冊請求了: ~~~ var address = "localhost:7054" conn, err := grpc.Dial(address, grpc.WithInsecure()) // 連接address中指定的grpc端口 defer conn.Close() ecaa := protos.NewECAAClient(conn) token, err := ecaa.RegisterUser(context.Background(), registerUserReq) ~~~ **注冊成功返回值** 一旦注冊成功,token即可接收到方法返回值,token是個結構體: ~~~ // ca.pb.go type Token struct { Tok []byte `protobuf:"bytes,1,opt,name=tok,proto3" json:"tok,omitempty"` } ~~~ token.Tok即為新用戶的enrollPwd。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看