美文网首页Go语言用例
golang如何访问一个结构体(struct)的未导出域(fie

golang如何访问一个结构体(struct)的未导出域(fie

作者: CodingCode | 来源:发表于2018-11-09 15:49 被阅读0次

golang如何访问一个结构体(struct)的未导出域(field)

问题的引出

在做fabric调试的时候,经常碰到证书验证失败的问题,看到orderer日志类似:

<orderer>  | <timestampe> [cauthdsl] deduplicate -> ERRO 177 Principal deserialization failure (the supplied
 identity is not valid: x509: certificate signed by unknown authority (possibly because of "x509: ECDSA
 verification failure" while trying to verify candidate authority certificate "...")) for identity <identify content>

在这个过程中打出来的是被验证的证书的内容(通过前面文章我们知道可以从identity导出证书的PEM格式),但是没有打印出验证所需要的CA证书信息,怎么办呢。我们需要得到验证所用到的CA证书信息。

溯源CA证书信息

msp对象(实际是bccspmsp struct)包含一个成员opts:

# fabric/msp/mspimpl.go
type bccspmsp struct {
  ...
  // verification options for MSP members
  opts *x509.VerifyOptions
  ...
}

opts是一个x509.VerifyOptions对象。

# go/src/crypto/x509/verify.go
type VerifyOptions struct {
  ...
  Intermediates *CertPool
  Roots         *CertPool // if nil, the system roots are used
  ...
}

VerifyOptions包含一个Roots和Intermediates,这两个pool里面的证书是用来验证证书的根证书。正好这两个变量都是导出变量(首字母大写),可以直接使用。
下面看CertPool的定义。

# go/src/crypto/x509/cert_pool.go
type CertPool struct {
        bySubjectKeyId map[string][]int
        byName         map[string][]int
        certs          []*Certificate
}

我们看到所有的证书都存在certs这个域里面,他是一个slice类型变量,只是遗憾的是certs不是一个导出变量(首字母小写),导致在包(package)外面不能访问这个域;另外CertPool也没有定义函数用来返回certs域,所有CertPool定义的导出函数只有如下:

func (s *CertPool) AddCert(cert *Certificate)
func (s *CertPool) AppendCertsFromPEM(pemCerts []byte) (ok bool)
func (s *CertPool) Subjects() [][]byte

这不抓瞎了吗,明明certs就定义在那里已经看到了,但是就是访问不了;库的设计者为什么要这样折磨人呢,为什么不暴露一个API导出这个slice呢,基于什么原因呢?

当然有一个办法,我们手动添加一个导出函数,在cert_pool.go文件内,例如:

func (s *CertPool) Certs() []*Certificate {
  return c.certs
}

不过要提醒你的是,这可是golang的系统库啊,不是你的用户代码。请你不要随便改。

另一办法,就是本文要说的如何访问一个未导出域。
CertPool的certs是一个未导出域,我们已经得到了CertPool对象,并且知道他有一个域certs包含的就是CA证书列表,下面我们就是想办法访问这个未导出域。

访问未导出域

使用reflect包访问struct的未导出域。

package main

import (
    "fmt"
    "reflect"
    "unsafe"
    "crypto/x509"
)

func main() {
    var certPool *x509.CertPool
    var err error
    if certPool, err = x509.SystemCertPool(); err != nil {
        panic(err)
    }

    var reflectStruct reflect.Value = reflect.ValueOf(certPool).Elem()
    var reflectField reflect.Value = reflectStruct.FieldByName("certs")

    fmt.Printf("reflectStruct type=[%v]\n", reflectStruct.Type())
    fmt.Printf("reflectField  type=[%v]\n", reflectField.Type())

    reflectField = reflect.NewAt(reflectField.Type(), unsafe.Pointer(reflectField.UnsafeAddr()))
    reflectField = reflectField.Elem()

    var certs []*x509.Certificate = reflectField.Interface().([]*x509.Certificate)
    fmt.Printf("Total Certificate: %d\n", len(certs))
    for i, cert := range certs {
        if content, err := certToPEM(cert); err != nil {
            panic(err)
        } else {
            fmt.Printf("Certificate[%d]=[%s]\n", i, content)
        }
    }
}

几个API:

  • func ValueOf(i interface{}) Value
    ValueOf returns a new Value initialized to the concrete value stored in the interface i
  • func (v Value) Elem() Value
    Elem returns the value that the interface v contains or that the pointer v points to
  • func (v Value) Interface() (i interface{})
    Interface returns v's current value as an interface{}
  • func NewAt(typ Type, p unsafe.Pointer) Value
    NewAt returns a Value representing a pointer to a value of the specified type, using p as that pointer

相关文章

  • golang如何访问一个结构体(struct)的未导出域(fie

    golang如何访问一个结构体(struct)的未导出域(field) 问题的引出 在做fabric调试的时候,经...

  • golang如何修改struct的未导出的域

    golang如何修改struct的未导出的域 这里例子说明如何使用reflect包来访问修改未导出的域。假设定义了...

  • rpc

    golang的rpc必须符合4个条件: 结构体首字母大写。跨域访问 函数名首字母大写。 序列化导出 函数第一个参数...

  • Golang struct

    Golang struct 一个结构体(struct)就是一个字段的集合 type Vertex str...

  • Golang——结构体struct

    Go语言中没有“类”的改变,不支持类的“继承”等面向对象概念。Go语言中通过结构体的内嵌再配合接口比面向对象更具有...

  • 2017.9.18学习总结

    今天学习了结构体,一般形式为struct 结构体名{成员列表};,每一个成员是结构体中的一个域,成员名命名规则与...

  • C语言结构体、共同体

    1、结构体 基本语法: 可使用.语法直接访问结构体中的成员。 结构体重命名: 使用typedef struct [...

  • Golang笔记: 结构体(struct)

    结构体定义 go语言的关键字 type 可以将各种基本类型定义为自定义类型,包括整型、字符串、布尔等。结构体是一种...

  • Golang 入门 : 结构体(struct)

    Go 通过类型别名(alias types)和结构体的形式支持用户自定义类型,或者叫定制类型。试图表示一个现实世界...

  • 结构体

    声明:结构体是一种自定义的数据类型 定义: struct 结构体名 变量名 = {初值}; 结构体成员访问: 匿名...

网友评论

    本文标题:golang如何访问一个结构体(struct)的未导出域(fie

    本文链接:https://www.haomeiwen.com/subject/hjloxqtx.html