forked from silenceper/wechat
-
Notifications
You must be signed in to change notification settings - Fork 0
/
callback.go
98 lines (90 loc) · 3.18 KB
/
callback.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
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
}