Ver Fonte

feat:支持微信客服回调请求的校验和消息的解析,复用原有的Signature和DecryptMsg方法 (#439)

* 添加微信客服SDK

* polish:优化签名函数

* polish:优化注释内容

* polish:复用已有的Token以及CommonError,移除无用的输出

* polish:复用已有的消息加解密

* fix:修复错误信息被覆盖的问题

* polish:go fmt 文件

* polish:客服链接支持自定义参数并更新注释文档内容

* feat:支持微信客服回调请求的校验和消息的解析,复用原有的Signature和DecryptMsg方法
Afeyer há 4 anos atrás
pai
commit
917f1817e5
3 ficheiros alterados com 104 adições e 10 exclusões
  1. 96 0
      work/kf/callback.go
  2. 8 0
      work/kf/error.go
  3. 0 10
      work/kf/syncmsg/callback.go

+ 96 - 0
work/kf/callback.go

@@ -0,0 +1,96 @@
+package kf
+
+import (
+	"encoding/xml"
+
+	"github.com/silenceper/wechat/v2/util"
+)
+
+// SignatureOptions 微信服务器验证参数
+type SignatureOptions struct {
+	Signature string `form:"msg_signature"`
+	TimeStamp string `form:"timestamp"`
+	Nonce     string `form:"nonce"`
+	EchoStr   string `form:"echostr"`
+}
+
+// VerifyURL 验证请求参数是否合法并返回解密后的消息内容
+//  //Gin框架的使用示例
+//	r.GET("/v1/event/callback", func(c *gin.Context) {
+//		options := kf.SignatureOptions{}
+//		//获取回调的的校验参数
+//		if = c.ShouldBindQuery(&options); err != nil {
+//			c.String(http.StatusUnauthorized, "参数解析失败")
+//		}
+//		// 调用VerifyURL方法校验当前请求,如果合法则把解密后的内容作为响应返回给微信服务器
+//		echo, err := kfClient.VerifyURL(options)
+//		if err == nil {
+//			c.String(http.StatusOK, echo)
+//		} else {
+//			c.String(http.StatusUnauthorized, "非法请求来源")
+//		}
+//	})
+func (r *Client) VerifyURL(options SignatureOptions) (string, error) {
+	if options.Signature != util.Signature(r.ctx.Token, options.TimeStamp, options.Nonce, options.EchoStr) {
+		return "", NewSDKErr(40015)
+	}
+	_, bData, err := util.DecryptMsg(r.corpID, options.EchoStr, r.encodingAESKey)
+	if err != nil {
+		return "", NewSDKErr(40016)
+	}
+
+	return string(bData), nil
+}
+
+// 原始回调消息内容
+type callbackOriginMessage struct {
+	ToUserName string // 企业微信的CorpID,当为第三方套件回调事件时,CorpID的内容为suiteid
+	AgentID    string // 接收的应用id,可在应用的设置页面获取
+	Encrypt    string // 消息结构体加密后的字符串
+}
+
+// CallbackMessage 微信客服回调消息
+type CallbackMessage struct {
+	ToUserName string `json:"to_user_name"` // 微信客服组件ID
+	CreateTime int    `json:"create_time"`  // 消息创建时间,unix时间戳
+	MsgType    string `json:"msgtype"`      // 消息的类型,此时固定为 event
+	Event      string `json:"event"`        // 事件的类型,此时固定为 kf_msg_or_event
+	Token      string `json:"token"`        // 调用拉取消息接口时,需要传此token,用于校验请求的合法性
+}
+
+// GetCallbackMessage 获取回调事件中的消息内容
+//  //Gin框架的使用示例
+//	r.POST("/v1/event/callback", func(c *gin.Context) {
+//		var (
+//			message kf.CallbackMessage
+//			body []byte
+//		)
+//		// 读取原始消息内容
+//		body, err = c.GetRawData()
+//		if err != nil {
+//			c.String(http.StatusInternalServerError, err.Error())
+//			return
+//		}
+//		// 解析原始数据
+//		message, err = kfClient.GetCallbackMessage(body)
+//		if err != nil {
+//			c.String(http.StatusInternalServerError, "消息获取失败")
+//			return
+//		}
+//		fmt.Println(message)
+//		c.String(200, "ok")
+//	})
+func (r *Client) GetCallbackMessage(encryptedMsg []byte) (msg CallbackMessage, err error) {
+	var origin callbackOriginMessage
+	if err = xml.Unmarshal(encryptedMsg, &origin); err != nil {
+		return msg, err
+	}
+	_, bData, err := util.DecryptMsg(r.corpID, origin.Encrypt, r.encodingAESKey)
+	if err != nil {
+		return msg, NewSDKErr(40016)
+	}
+	if err = xml.Unmarshal(bData, &msg); err != nil {
+		return msg, err
+	}
+	return msg, err
+}

+ 8 - 0
work/kf/error.go

@@ -21,6 +21,10 @@ const (
 	SDKInvalidCorpID Error = "无效的 CorpID"
 	// SDKAccessTokenInvalid 错误码:40014
 	SDKAccessTokenInvalid Error = "AccessToken 无效"
+	// SDKValidateSignatureFailed 错误码:40015
+	SDKValidateSignatureFailed Error = "校验签名错误"
+	// SDKDecryptMSGFailed 错误码:40016
+	SDKDecryptMSGFailed Error = "消息解密失败"
 	// SDKAccessTokenMissing 错误码:41001
 	SDKAccessTokenMissing Error = "缺少AccessToken参数"
 	// SDKAccessTokenExpired 错误码:42001
@@ -53,6 +57,10 @@ func NewSDKErr(code int64, msgList ...string) Error {
 		return SDKInvalidCorpID
 	case 40014:
 		return SDKAccessTokenInvalid
+	case 40015:
+		return SDKValidateSignatureFailed
+	case 40016:
+		return SDKDecryptMSGFailed
 	case 45009:
 		return SDKApiFreqOutOfLimit
 	case 95011:

+ 0 - 10
work/kf/syncmsg/callback.go

@@ -1,10 +0,0 @@
-package syncmsg
-
-// Event 微信客服回调事件
-type Event struct {
-	ToUserName string `json:"to_user_name"` // 微信客服组件ID
-	CreateTime int    `json:"create_time"`  // 消息创建时间,unix时间戳
-	MsgType    string `json:"msgtype"`      // 消息的类型,此时固定为 event
-	Event      string `json:"event"`        // 事件的类型,此时固定为 kf_msg_or_event
-	Token      string `json:"token"`        // 调用拉取消息接口时,需要传此token,用于校验请求的合法性
-}