• Fabric-ca client端初始化过程源码分析


    本文从Fabric-ca源码入手,以newRegisterCommand()函数为例,简单分析client启动时的过程。Fabric-ca源码可以从github.com下载,本文以v1.4.6为例进行简单分析。

    与server相似,本文也是从main.go开始:

    // fabric-ca/cmd/fabric-ca-client/main.go
    
    package main
    
    import (
    	...
    )
    
    // The fabric-ca client main
    func main() {
    	if err := command.RunMain(os.Args); err != nil {
    		os.Exit(1)
    	}
    }
    

    main()函数只是调用了package command中的RunMain()函数,所以接下来我们以RunMain()函数为起点来简析client端的启动过程,其中包括client端的初始化以及跟server端的初次交互:

    // fabric-ca/cmd/fabric-ca-client/command/root.go  
    
    package command
    
    import "os"
    
    // RunMain is the fabric-ca client main
    func RunMain(args []string) error {
    	// Save the os.Args
    	saveOsArgs := os.Args
    	os.Args = args
    
    	// Execute the command
    	cmdName := ""
    	if len(args) > 1 {
    		cmdName = args[1]
    	}
    	ccmd := NewCommand(cmdName)
    	err := ccmd.Execute()
    
    	// Restore original os.Args
    	os.Args = saveOsArgs
    
    	return err
    }
    

    不难看出,与server类似,都是先通过NewCommand()函数来添加命令,之后再通过Execute()来执行操作:

    // fabric-ca/cmd/fabric-ca-client/command/clientcmd.go
    
    // ClientCmd encapsulates cobra command that provides command line interface
    // for the Fabric CA client and the configuration used by the Fabric CA client
    type ClientCmd struct {
    	// name of the sub command
    	name string
    	// rootCmd is the base command for the Hyerledger Fabric CA client
    	rootCmd *cobra.Command
    	// My viper instance
    	myViper *viper.Viper
    	// cfgFileName is the name of the configuration file
    	cfgFileName string
    	// homeDirectory is the location of the client's home directory
    	homeDirectory string
    	// clientCfg is the client's configuration
    	clientCfg *lib.ClientConfig
    	// cfgAttrs are the attributes specified via flags or env variables
    	// and translated to Attributes field in registration
    	cfgAttrs []string
    	// cfgAttrReqs are the attribute requests specified via flags or env variables
    	// and translated to the AttrReqs field in enrollment
    	cfgAttrReqs []string
    	// cfgCsrNames are the certificate signing request names specified via flags
    	// or env variables
    	cfgCsrNames []string
    	// csrCommonName is the certificate signing request common name specified via the flag
    	csrCommonName string
    	// gencrl command argument values
    	crlParams crlArgs
    	// revoke command argument values
    	revokeParams revokeArgs
    	// profileMode is the profiling mode, cpu or mem or empty
    	profileMode string
    	// profileInst is the profiling instance object
    	profileInst interface {
    		Stop()
    	}
    	// Dynamically configuring identities
    	dynamicIdentity identityArgs
    	// Dynamically configuring affiliations
    	dynamicAffiliation affiliationArgs
    	// Set to log level
    	logLevel string
    }
    
    // NewCommand returns new ClientCmd ready for running
    func NewCommand(name string) *ClientCmd {
    	c := &ClientCmd{
    		myViper: viper.New(),
    	}
    	c.name = strings.ToLower(name)
    	c.init()
    	return c
    }
    
    ...
    
    // init initializes the ClientCmd instance
    // It intializes the cobra root and sub commands and
    // registers command flgs with viper
    func (c *ClientCmd) init() {
    	...
    
    	c.rootCmd.AddCommand(c.newRegisterCommand(),
    		newEnrollCmd(c).getCommand(),
    		c.newReenrollCommand(),
    		c.newRevokeCommand(),
    		newGetCAInfoCmd(c).getCommand(),
    		c.newGenCsrCommand(),
    		c.newGenCRLCommand(),
    		c.newIdentityCommand(),
    		c.newAffiliationCommand(),
    		createCertificateCommand(c))
    	c.rootCmd.AddCommand(&cobra.Command{
    		Use:   "version",
    		Short: "Prints Fabric CA Client version",
    		Run: func(cmd *cobra.Command, args []string) {
    			fmt.Print(metadata.GetVersionInfo(cmdName))
    		},
    	})
    	c.registerFlags()
    	...
    }
    

    NewCommand()函数中,创建了一个*ClientCmd的对象,之后,调用该对象的init()方法。在init()方法中,首先实例化了*ClientCmd.rootCmd,其中会要执行checkAndEnableProfiling()来检查运行环境:

    // checkAndEnableProfiling checks for the FABRIC_CA_CLIENT_PROFILE_MODE
    // env variable, if it is set to "cpu", cpu profiling is enbled;
    // if it is set to "heap", heap profiling is enabled
    func (c *ClientCmd) checkAndEnableProfiling() error {
    	...
    }
    
    // registerFlags registers command flags with viper
    func (c *ClientCmd) registerFlags() {
    	...
    }
    

    之后会调用AddCommand()函数来添加newRegisterCommand()newEnrollCmd(c).getCommand()newReenrollCommand()newRevokeCommand()newGetCAInfoCmd(c).getCommand()newGenCsrCommand()newGenCRLCommand()newIdentityCommand()newAffiliationCommand()createCertificateCommand()和获取client版本的命令。随后执行c.registerFlags()操作。registerFlags()函数中主要是注册一些命令行参数,这里就不细究了。

    newRegisterCommand()

    // fabric-ca/cmd/fabric-ca-client/command/register.go
    
    func (c *ClientCmd) newRegisterCommand() *cobra.Command {
    	...
    }
    
    // The client register main logic
    func (c *ClientCmd) runRegister() error {
    	...
    }
    

    newRegisterCommand()函数中,实例化了一个*cobra.Command命令对象,该对象中包含两个命令:ConfigInit()runRegister()ConfigInit()命令是为fabric-ca-client命令初始化一些配置,这里不做说明,而runRegister()中包含客户端注册的主要逻辑:首先实例化一个lib.Client结构体,之后导入client端的身份凭证client.LoadMyIdentity(),随后发起注册*Identity.Register()

    // fabric-ca/lib/client.go
    
    // Client is the fabric-ca client object
    type Client struct {
    	// The client's home directory
    	HomeDir string `json:"homeDir,omitempty"`
    	// The client's configuration
    	Config *ClientConfig
    	// Denotes if the client object is already initialized
    	initialized bool
    	// File and directory paths
    	keyFile, certFile, idemixCredFile, idemixCredsDir, ipkFile, caCertsDir string
    	// The crypto service provider (BCCSP)
    	csp bccsp.BCCSP
    	// HTTP client associated with this Fabric CA client
    	httpClient *http.Client
    	// Public key of Idemix issuer
    	issuerPublicKey *idemix.IssuerPublicKey
    }
    
    // LoadMyIdentity loads the client's identity from disk
    func (c *Client) LoadMyIdentity() (*Identity, error) {
    	...
    	return c.LoadIdentity(c.keyFile, c.certFile, c.idemixCredFile)
    }
    
    // LoadIdentity loads an identity from disk
    func (c *Client) LoadIdentity(keyFile, certFile, idemixCredFile string) (*Identity, error) {
    	...
    	return c.NewIdentity(creds)
    }
    
    // NewIdentity creates a new identity
    func (c *Client) NewIdentity(creds []credential.Credential) (*Identity, error) {
    	...
    	return NewIdentity(c, name, creds), nil
    }
    

    如上,在LoadMyIdentity()中会先调用Init()来初始化client,然后再调用LoadIdentity()函数,从硬盘中导入身份凭证。在LoadIdentity()中同样会调用Init()来初始化client,之后会调用NewCredential()接口来导入x509idemin格式的证书。证书读取完成后,调用NewIdentity()来创建新的身份认证。至此,身份导入过程就完成了,接下来就是注册了。

    //fabric-ca/lib/identity.go
    
    // Register registers a new identity
    // @param req The registration request
    func (i *Identity) Register(req *api.RegistrationRequest) (rr *api.RegistrationResponse, err error) {
    	...
    }
    

    Register(),会将认证请求序列后,通过Post请求发送给服务端,并将服务端的应答返回给调用者。

    // Post sends arbitrary request body (reqBody) to an endpoint.
    // This adds an authorization header which contains the signature
    // of this identity over the body and non-signature part of the authorization header.
    // The return value is the body of the response.
    func (i *Identity) Post(endpoint string, reqBody []byte, result interface{}, queryParam map[string]string) error {
    	...
    }
    

    至此,注册命令就结束了。

  • 相关阅读:
    systemtap分析软raid io拆分问题
    Profiling Java Application with Systemtap
    中国南方ORACLE用户组
    Docker 核心技术与实现原理
    The Internals of PostgreSQL
    Alone_Monkey 逆向IOS
    淘宝内核月报 2017
    Linux kernel engineer--trace
    你的按钮到底在帮助用户还是在误导用户?
    2020年值得你去试试的10个React开发工具
  • 原文地址:https://www.cnblogs.com/lianshuiwuyi/p/12487033.html
Copyright © 2020-2023  润新知