package callback import ( "encoding/json" "encoding/xml" "fmt" "strconv" "strings" "time" "github.com/flipped-aurora/gin-vue-admin/server/commonus" "github.com/flipped-aurora/gin-vue-admin/server/global" "github.com/flipped-aurora/gin-vue-admin/server/model/common/response" "github.com/flipped-aurora/gin-vue-admin/server/model/wechatcallback" "github.com/flipped-aurora/gin-vue-admin/server/wechatjiexi/wxbizmsgcrypt" "github.com/gin-gonic/gin" ) //入口 func (a *CallBackApi) Index(c *gin.Context) { outPut := commonus.MapOut() response.Result(0, outPut, "企业微信回调入口", c) } //回调入口 func (a *CallBackApi) CallbackMessageApi(c *gin.Context) { MsgSignature := c.Query("msg_signature") //企业微信加密签名,msg_signature计算结合了企业填写的token、请求中的timestamp、nonce、加密的消息体。 Timestamp := c.Query("timestamp") //时间戳。与nonce结合使用,用于防止请求重放攻击。 Nonce := c.Query("nonce") //随机数。与timestamp结合使用,用于防止请求重放攻击。 Echostr := c.Query("echostr") //加密的字符串。需要解密得到消息内容明文,解密后有random、msg_len、msg、receiveid四个字段,其中msg即为消息内容明文 var basicValueCallback CallBackData //企业微信回调基础参数 basicValueCallback.MsgSignature = MsgSignature timeStampInt, timeStampIntErr := strconv.ParseInt(Timestamp, 10, 64) if timeStampIntErr == nil { basicValueCallback.Timestamp = timeStampInt } basicValueCallback.Nonce = Nonce if Echostr != "" { //Api地址验证 basicValueCallback.Echostr = Echostr msgStr := basicValueCallback.VerificationUrl() c.String(200, msgStr) } else { var xmlMessageStr CallBackVerificationXml xmlErr := c.ShouldBindXML(&xmlMessageStr) if xmlErr != nil { response.Result(101, xmlErr, "XML获取错误!", c) return } // fmt.Printf("Xml----->%v\n", xmlMessageStr) basicValueCallback.ToUserName = xmlMessageStr.ToUserName.Text basicValueCallback.Encrypt = xmlMessageStr.Encrypt.Text basicValueCallback.AgentID = xmlMessageStr.AgentID.Text msgStr := basicValueCallback.DecryptMessage() c.String(200, msgStr) } } //启动企业微信验证程序 func WechatVerification() (wxcpt *wxbizmsgcrypt.WXBizMsgCrypt) { //正式数据 // token := "kkUA3s2s3" token := global.GVA_CONFIG.WorkWechatSchool.WechatTokening receiverId := global.GVA_CONFIG.WorkWechatId.CompanyId encodingAeskey := global.GVA_CONFIG.WorkWechatSchool.EncodingAESKey // fmt.Printf("------->%v------->%v------->%v\n", token, receiverId, encodingAeskey) //测试数据 // token := "QDG6eK" // receiverId := "wx5823bf96d3bd56c7" // encodingAeskey := "jWmYm7qr5nMoAUwZRjGtBxmz3KA1tkAj3ykkR6q2B2C" wxcpt = wxbizmsgcrypt.NewWXBizMsgCrypt(token, encodingAeskey, receiverId, wxbizmsgcrypt.XmlType) return } //验证URL func (c *CallBackData) VerificationUrl() (msg string) { wecahtCpt := WechatVerification() timestampStr := strconv.FormatInt(c.Timestamp, 10) echoStr, cryptErr := wecahtCpt.VerifyURL(c.MsgSignature, timestampStr, c.Nonce, c.Echostr) var callbackLog wechatcallback.CallbackLog // callbackLog.MsgSignature = c.MsgSignature callbackLog.TimeStamp = c.Timestamp callbackLog.Nonce = c.Nonce callbackLog.Echostr = c.Echostr callbackLog.Xmlstr = string(echoStr) // callbackLog.Reqdata = string(reqData) callbackLog.AddTime = time.Now().Unix() global.GVA_DB_WechatCallBack.Create(&callbackLog) if nil != cryptErr { fmt.Println("verifyUrl fail", cryptErr) } msg = string(echoStr) return // fmt.Println(string(echoStr)) // fmt.Print(string(echoStr)) } //解析消息结构 func (c *CallBackData) DecryptMessage() (echoMsg string) { wecahtCpt := WechatVerification() timestampStr := strconv.FormatInt(c.Timestamp, 10) reqData := []byte("") msg, cryptErr := wecahtCpt.DecryptMsg(c.MsgSignature, timestampStr, c.Nonce, reqData) // fmt.Printf("%v=====>%v=====>%v\n: ", c.ToUserName, c.Encrypt, c.AgentID) if nil != cryptErr { fmt.Println("DecryptMsg fail", cryptErr) } // fmt.Println("after decrypt msg: ", string(msg)) var msgContent MsgContent err := xml.Unmarshal(msg, &msgContent) if nil != err { fmt.Println("Unmarshal fail") } // fmt.Printf("1========>%v========>%v\n ", msgContent.MsgType, msgContent.Event) switch msgContent.MsgType { /*消息格式类型 */ case "text": //文本 case "image": //图片 case "voice": //语音 case "video": //视频 case "location": //位置 case "link": //链接 /*事件格式类型*/ case "event": /* 事件附属格式 */ echoMsg = EventProcessing(msgContent.Event, msg, c) return default: } var callbackLog wechatcallback.CallbackLog // callbackLog.MsgSignature = c.MsgSignature callbackLog.TimeStamp = c.Timestamp callbackLog.Nonce = c.Nonce callbackLog.Echostr = c.Echostr callbackLog.Xmlstr = string(msg) callbackLog.Reqdata = string(reqData) msgCont, jsonErr := json.Marshal(msgContent) if jsonErr == nil { callbackLog.Jsonstr = string(msgCont) } callbackLog.AddTime = time.Now().Unix() if msgContent.Event != "LOCATION" { global.GVA_DB_WechatCallBack.Create(&callbackLog) } return } //企业微信事件处理 func EventProcessing(event string, decryptMsg []byte, v *CallBackData) (msg string) { var msgContent MsgContentMailList err := xml.Unmarshal(decryptMsg, &msgContent) if nil != err { fmt.Println("Unmarshal fail") } switch event { case "subscribe": //关注 case "unsubscribe": //取消关注 case "enter_agent": //本事件在成员进入企业微信的应用时触发 case "LOCATION": //上报地理位置 GeographicalPosition(decryptMsg) case "batch_job_result": //异步任务完成事件推送 case "change_contact": //通讯录变更事件 WorkWechatMailList(msgContent.ChangeType, decryptMsg) case "click": //点击菜单拉取消息的事件推送 case "view": //点击菜单跳转链接的事件推送 case "scancode_push": //扫码推事件的事件推送 case "scancode_waitmsg": //扫码推事件且弹出“消息接收中”提示框的事件推送 case "pic_sysphoto": //弹出系统拍照发图的事件推送 case "pic_photo_or_album": //弹出拍照或者相册发图的事件推送 case "pic_weixin": //弹出微信相册发图器的事件推送 case "location_select": //弹出地理位置选择器的事件推送 case "open_approval_change": //审批状态通知事件 自建应用 OpenApprovalChange(decryptMsg) case "sys_approval_change": //系统审批应用 case "share_agent_change": //企业互联共享应用事件回调 case "share_chain_change": //上下游共享应用事件回调 case "template_card_event": //模板卡片事件推送 var msgContent TemplateCardPush err := xml.Unmarshal(decryptMsg, &msgContent) if nil != err { fmt.Println("***********Unmarshal fail") } buttonClick := strings.Split(msgContent.EventKey, "_") buttonClickNAme := "已批准" if len(buttonClick) >= 3 { if buttonClick[2] != "1" { buttonClickNAme = "已驳回" } } fmt.Printf("***********%v------------->%v------------->%v\n", buttonClick, buttonClick[2], msgContent) xmlReply := fmt.Sprintf("%v", msgContent.ToUsername, msgContent.FromUsername, msgContent.CreateTime, buttonClickNAme) wecahtCpt := WechatVerification() timestampStr := strconv.FormatInt(v.Timestamp, 10) encryptMsg, cryptErr := wecahtCpt.EncryptMsg(xmlReply, timestampStr, v.Nonce) if cryptErr == nil { msg = string(encryptMsg) } else { msg = "25000" } templateEventPush(decryptMsg) case "template_card_menu_event": //通用模板卡片右上角菜单事件推送 default: } return } //企业微信通讯录变更事件处理 func WorkWechatMailList(changeType string, decryptMsg []byte) { switch changeType { case "create_party": //新增部门事件 case "update_party": //更新部门事件 case "delete_party": //删除部门事件 case "update_tag": //标签成员变更事件 case "batch_job_result": //异步任务完成事件推送 case "change_contact": //通讯录变更事件 case "create_user": //新增成员事件 case "update_user": //更新成员事件 case "delete_user": //删除成员事件 default: } }