消息通知服务 SMN-示例代码:Go语言

时间:2024-04-17 18:15:02

Go语言

package demo

import (
	"bytes"
	"crypto"
	"crypto/rsa"
	"crypto/x509"
	"encoding/base64"
	"encoding/json"
	"encoding/pem"
	"fmt"
	"io/ioutil"
)

type Message struct {
	Signature        string  `json:"signature"`
	Subject          *string `json:"subject"`
	TopicUrn         string  `json:"topic_urn"`
	MessageId        string  `json:"message_id"`
	SignatureVersion string  `json:"signature_version"`
	Type             string  `json:"type"`
	Message          string  `json:"message"`
	SubscribeUrl     string  `json:"subscribe_url"`
	UnsubscribeUrl   string  `json:"unsubscribe_url"`
	SigningCertUrl   string  `json:"signing_cert_url"`
	Timestamp        string  `json:"timestamp"`
}

func VerifyMessage(pemFile string, message string) bool {
	msg := Message{}
	err := json.Unmarshal([]byte(message), &msg)
	if err != nil {
		fmt.Println("Convert json to struct failed")
		return false
	}
	pemContent, err := ioutil.ReadFile(pemFile)
	if err != nil {
		fmt.Println("Read pem file failed")
		return false
	}
	certDerblock, _ := pem.Decode(pemContent)
	if certDerblock == nil {
		fmt.Println("Decode pem file failed")
		return false
	}
	cert, err := x509.ParseCertificate(certDerblock.Bytes)
	if err != nil {
		fmt.Println("Parse cert failed")
		return false
	}

	msgString := buildMessage(&msg)
	msgHash := crypto.SHA256.New()
	msgHash.Write([]byte(msgString))
	msgHashSum := msgHash.Sum(nil)

	decodeSign, _ := base64.StdEncoding.DecodeString(msg.Signature)

	publicKey := cert.PublicKey.(*rsa.PublicKey)
	err = rsa.VerifyPKCS1v15(publicKey, crypto.SHA256, msgHashSum, decodeSign)
	if err != nil {
		fmt.Println("Verify failed")
		return false
	} else {
		fmt.Println("Verify success")
		return true
	}
}

func buildMessage(msg *Message) string {
	if msg.Type == "Notification" {
		return buildNotificationMessage(msg)
	} else if msg.Type == "SubscriptionConfirmation" || msg.Type == "UnsubscribeConfirmation" {
		return buildSubscriptionMessage(msg)
	}
	return ""
}

func buildNotificationMessage(msg *Message) string {
	buf := bytes.Buffer{}
	buf.WriteString("message\n" + msg.Message + "\n")
	buf.WriteString("message_id\n" + msg.MessageId + "\n")
	// msg中存在Subject字段不存在的场景,需要特殊处理
	if msg.Subject != nil {
		buf.WriteString("subject\n" + *msg.Subject + "\n")
	}
	buf.WriteString("timestamp\n" + msg.Timestamp + "\n")
	buf.WriteString("topic_urn\n" + msg.TopicUrn + "\n")
	buf.WriteString("type\n" + msg.Type + "\n")
	return buf.String()
}

func buildSubscriptionMessage(msg *Message) string {
	buf := bytes.Buffer{}
	buf.WriteString("message\n" + msg.Message + "\n")
	buf.WriteString("message_id\n" + msg.MessageId + "\n")
	buf.WriteString("subscribe_url\n" + msg.SubscribeUrl + "\n")
	buf.WriteString("timestamp\n" + msg.Timestamp + "\n")
	buf.WriteString("topic_urn\n" + msg.TopicUrn + "\n")
	buf.WriteString("type\n" + msg.Type + "\n")
	return buf.String()
}

该示例代码已在go 1.15版本上测试通过。

support.huaweicloud.com/usermanual-smn/smn_ug_a9004.html