dddd
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

296 lines
10 KiB

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/utils/redishandel"
"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
basicValueCallback.DecryptMessage(c)
// msgStr := basicValueCallback.DecryptMessage(c)
// 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(cs *gin.Context) (echoMsg string) {
wecahtCpt := WechatVerification()
timestampStr := strconv.FormatInt(c.Timestamp, 10)
reqData := []byte("<xml><ToUserName><![CDATA[" + c.ToUserName + "]]></ToUserName><Encrypt><![CDATA[" + c.Encrypt + "]]></Encrypt><AgentID><![CDATA[" + c.AgentID + "]]></AgentID></xml>")
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, cs)
// return
default:
}
// fmt.Printf("yyyyyyyy------------->%v\n", 123456)
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()
var redisList WechatCallBackRedis
redisList.MsgSignature = c.MsgSignature
redisList.TimeStamp = c.Timestamp
redisList.Nonce = c.Nonce
redisList.Echostr = c.Echostr
redisList.Xmlstr = string(msg)
redisList.Reqdata = string(reqData)
msgContr, jsonrErr := json.Marshal(msgContent)
if jsonrErr == nil {
redisList.Jsonstr = string(msgContr)
}
redisList.AddTime = time.Now().Unix()
redisList.Content = msgContent
jsonStr, jsonRedisErr := json.Marshal(redisList)
// redisClient := redishandel.RunRedis()
// redisClient.SetRedisDb(2)
// redisClient.SetRedisTime(0)
redisPrefix := fmt.Sprintf("Wechat:CallBack_%v:XML_%v", global.GVA_CONFIG.RedisPrefix.PreFix, msgContent.Event) //redis KEY
// redisClient.Lpush(redisPrefix, string(jsonStr))
if jsonRedisErr == nil {
WechatCallBackDataWruteRedis(redisPrefix, string(jsonStr), "lpush")
}
// fmt.Printf("yyyyyyyy------------->%v\n", string(jsonStr))
if msgContent.Event != "LOCATION" {
global.GVA_DB_WechatCallBack.Create(&callbackLog)
}
return
}
//企业微信事件处理
func EventProcessing(event string, decryptMsg []byte, v *CallBackData, cs *gin.Context) (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("<xml><ToUserName><![CDATA[%v]]></ToUserName><FromUserName><![CDATA[%v]]></FromUserName><CreateTime>%v</CreateTime><MsgType><![CDATA[update_button]]></MsgType><Button><ReplaceName><![CDATA[%v]]></ReplaceName></Button></xml>", 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"
}
synergeticProcess.Add(1)
go templateEventPush(decryptMsg)
defer synergeticProcess.Wait()
cs.String(200, msg)
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:
}
}
//回调写入redis
func WechatCallBackDataWruteRedis(redisKey, redisVal, class string) {
redisClient := redishandel.RunRedis()
redisClient.SetRedisDb(2)
redisClient.SetRedisTime(0)
switch class {
case "lpush": //列表
locationJson, locationErr := redisClient.Lindex(redisKey, 0)
if locationErr != nil {
redisClient.Lpush(redisKey, redisVal)
} else {
var geographicalPositionRedis GeographicalPositionRedis
jsonErr := json.Unmarshal([]byte(locationJson), &geographicalPositionRedis)
if jsonErr != nil {
redisClient.Lpush(redisKey, redisVal)
} else {
timeVal := geographicalPositionRedis.Time
if time.Now().Unix()-timeVal >= 300 {
redisClient.Lpush(redisKey, redisVal)
}
}
}
default:
redisClient.Set(redisKey, redisVal)
}
}