callback.go 3.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. package kf
  2. import (
  3. "encoding/xml"
  4. "github.com/silenceper/wechat/v2/util"
  5. )
  6. // SignatureOptions 微信服务器验证参数
  7. type SignatureOptions struct {
  8. Signature string `form:"msg_signature"`
  9. TimeStamp string `form:"timestamp"`
  10. Nonce string `form:"nonce"`
  11. EchoStr string `form:"echostr"`
  12. }
  13. // VerifyURL 验证请求参数是否合法并返回解密后的消息内容
  14. //
  15. // //Gin 框架的使用示例
  16. // r.GET("/v1/event/callback", func(c *gin.Context) {
  17. // options := kf.SignatureOptions{}
  18. // //获取回调的的校验参数
  19. // if = c.ShouldBindQuery(&options); err != nil {
  20. // c.String(http.StatusUnauthorized, "参数解析失败")
  21. // }
  22. // // 调用 VerifyURL 方法校验当前请求,如果合法则把解密后的内容作为响应返回给微信服务器
  23. // echo, err := kfClient.VerifyURL(options)
  24. // if err == nil {
  25. // c.String(http.StatusOK, echo)
  26. // } else {
  27. // c.String(http.StatusUnauthorized, "非法请求来源")
  28. // }
  29. // })
  30. func (r *Client) VerifyURL(options SignatureOptions) (string, error) {
  31. if options.Signature != util.Signature(r.ctx.Token, options.TimeStamp, options.Nonce, options.EchoStr) {
  32. return "", NewSDKErr(40015)
  33. }
  34. _, bData, err := util.DecryptMsg(r.corpID, options.EchoStr, r.encodingAESKey)
  35. if err != nil {
  36. return "", NewSDKErr(40016)
  37. }
  38. return string(bData), nil
  39. }
  40. // 原始回调消息内容
  41. type callbackOriginMessage struct {
  42. ToUserName string // 企业微信的 CorpID,当为第三方套件回调事件时,CorpID 的内容为 suiteid
  43. AgentID string // 接收的应用 id,可在应用的设置页面获取
  44. Encrypt string // 消息结构体加密后的字符串
  45. }
  46. // CallbackMessage 微信客服回调消息
  47. type CallbackMessage struct {
  48. ToUserName string `json:"to_user_name" xml:"ToUserName"` // 微信客服组件 ID
  49. CreateTime int64 `json:"create_time" xml:"CreateTime"` // 消息创建时间,unix 时间戳
  50. MsgType string `json:"msgtype" xml:"MsgType"` // 消息的类型,此时固定为 event
  51. Event string `json:"event" xml:"Event"` // 事件的类型,此时固定为 kf_msg_or_event
  52. Token string `json:"token" xml:"Token"` // 调用拉取消息接口时,需要传此 token,用于校验请求的合法性
  53. OpenKfID string `json:"open_kfid" xml:"OpenKfId"` // 有新消息的客服帐号。可通过 sync_msg 接口指定 open_kfid 获取此客服帐号的消息
  54. }
  55. // GetCallbackMessage 获取回调事件中的消息内容
  56. //
  57. // //Gin 框架的使用示例
  58. // r.POST("/v1/event/callback", func(c *gin.Context) {
  59. // var (
  60. // message kf.CallbackMessage
  61. // body []byte
  62. // )
  63. // // 读取原始消息内容
  64. // body, err = c.GetRawData()
  65. // if err != nil {
  66. // c.String(http.StatusInternalServerError, err.Error())
  67. // return
  68. // }
  69. // // 解析原始数据
  70. // message, err = kfClient.GetCallbackMessage(body)
  71. // if err != nil {
  72. // c.String(http.StatusInternalServerError, "消息获取失败")
  73. // return
  74. // }
  75. // fmt.Println(message)
  76. // c.String(200, "ok")
  77. // })
  78. func (r *Client) GetCallbackMessage(encryptedMsg []byte) (msg CallbackMessage, err error) {
  79. var origin callbackOriginMessage
  80. if err = xml.Unmarshal(encryptedMsg, &origin); err != nil {
  81. return msg, err
  82. }
  83. _, bData, err := util.DecryptMsg(r.corpID, origin.Encrypt, r.encodingAESKey)
  84. if err != nil {
  85. return msg, NewSDKErr(40016)
  86. }
  87. err = xml.Unmarshal(bData, &msg)
  88. return msg, err
  89. }