You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

求助:基于上层Type字段实现VerifyingKey的自定义JSON反序列化

解决方案

要实现这个需求,核心思路是给SingleKey结构体实现自定义的JSON反序列化方法——因为VerifyingKey的解析逻辑依赖上层的Type字段,单独给OtherFields写反序列化拿不到Type的值,所以必须从顶层结构体入手。

具体实现步骤如下:

  1. 定义临时结构体,先解析出Type和OtherFields的大部分字段,把VerifyingKey保留为原始JSON字节(用json.RawMessage),避免提前解析出错。
  2. 在SingleKey的UnmarshalJSON方法里,先将JSON解析到临时结构体,再根据Type字段的值,把VerifyingKey的原始JSON解析成对应的具体PublicKey实现类型切片。
  3. 针对不同密钥类型编写解析逻辑,同时处理错误场景。

完整代码示例:

package main

import (
	"encoding/json"
	"errors"
	"fmt"
)

type SingleKey struct {
	Type   string       `json:"type"`
	Others OtherFields `json:"wrapped_fields"`
}

type OtherFields struct {
	FQDN         string      `json:"fqdn"`
	Address      string      `json:"address"`
	Nonce        int64       `json:"nonce"`
	Challenge    []byte      `json:"challenge"`
	NetworkID    string      `json:"network_id"`
	VerifyingKey []PublicKey `json:"verifying_key"`
	Signature    []byte      `json:"signature"`
}

// PublicKey 公钥接口
type PublicKey interface {
	KeyType() string // 标识密钥类型,用于类型断言或区分
}

// RsaPublicKey RSA公钥具体实现
type RsaPublicKey struct {
	Modulus string `json:"modulus"`
	Exponent int   `json:"exponent"`
}

func (r RsaPublicKey) KeyType() string {
	return "rsa"
}

// EcdsaPublicKey ECDSA公钥具体实现
type EcdsaPublicKey struct {
	Curve string `json:"curve"`
	X     string `json:"x"`
	Y     string `json:"y"`
}

func (e EcdsaPublicKey) KeyType() string {
	return "ecdsa"
}

// 临时结构体,用于中间解析
type tempSingleKey struct {
	Type string `json:"type"`
	Others struct {
		FQDN         string          `json:"fqdn"`
		Address      string          `json:"address"`
		Nonce        int64           `json:"nonce"`
		Challenge    []byte          `json:"challenge"`
		NetworkID    string          `json:"network_id"`
		VerifyingKey json.RawMessage `json:"verifying_key"` // 保留原始JSON
		Signature    []byte          `json:"signature"`
	} `json:"wrapped_fields"`
}

// 给SingleKey实现自定义JSON反序列化
func (s *SingleKey) UnmarshalJSON(data []byte) error {
	var temp tempSingleKey
	if err := json.Unmarshal(data, &temp); err != nil {
		return err
	}

	// 先赋值普通字段
	s.Type = temp.Type
	s.Others.FQDN = temp.Others.FQDN
	s.Others.Address = temp.Others.Address
	s.Others.Nonce = temp.Others.Nonce
	s.Others.Challenge = temp.Others.Challenge
	s.Others.NetworkID = temp.Others.NetworkID
	s.Others.Signature = temp.Others.Signature

	// 根据Type解析VerifyingKey
	var verifyingKeys []PublicKey
	switch temp.Type {
	case "rsa":
		var rsaKeys []RsaPublicKey
		if err := json.Unmarshal(temp.Others.VerifyingKey, &rsaKeys); err != nil {
			return fmt.Errorf("解析RSA公钥失败: %w", err)
		}
		for _, key := range rsaKeys {
			verifyingKeys = append(verifyingKeys, key)
		}
	case "ecdsa":
		var ecdsaKeys []EcdsaPublicKey
		if err := json.Unmarshal(temp.Others.VerifyingKey, &ecdsaKeys); err != nil {
			return fmt.Errorf("解析ECDSA公钥失败: %w", err)
		}
		for _, key := range ecdsaKeys {
			verifyingKeys = append(verifyingKeys, key)
		}
	default:
		return errors.New("未知密钥类型: " + temp.Type)
	}

	s.Others.VerifyingKey = verifyingKeys
	return nil
}

// 测试代码
func main() {
	rsaJSON := `{
		"type": "rsa",
		"wrapped_fields": {
			"fqdn": "example.com",
			"address": "192.168.1.1",
			"nonce": 12345,
			"challenge": "YWJjZA==",
			"network_id": "test-net",
			"verifying_key": [
				{"modulus": "abc123", "exponent": 65537}
			],
			"signature": "dGhpcyBpcyBhIHNpZ25hdHVyZQ=="
		}
	}`

	var sk SingleKey
	if err := json.Unmarshal([]byte(rsaJSON), &sk); err != nil {
		fmt.Println("反序列化失败:", err)
		return
	}

	// 验证解析结果
	for _, key := range sk.Others.VerifyingKey {
		if rsaKey, ok := key.(RsaPublicKey); ok {
			fmt.Printf("解析得到RSA公钥: 模数=%s, 指数=%d\n", rsaKey.Modulus, rsaKey.Exponent)
		}
	}
}

关键说明:

  • 给PublicKey接口添加KeyType()方法,是Go语言中接口实现的规范要求,也方便后续区分不同密钥类型。
  • 临时结构体tempSingleKey的作用是先完成所有字段的初步解析,仅保留VerifyingKey的原始JSON,确保我们能拿到Type后再针对性解析。
  • 反序列化方法中先完成普通字段的赋值,再根据Type分支处理VerifyingKey,最后转换为[]PublicKey接口切片赋值给目标结构体。
  • 错误处理添加了明确的场景描述,方便调试定位问题。

内容的提问来源于stack exchange,提问作者Erdem Tuna

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 07:45:12