package global import ( base_ctl "SCRM/controllers" "SCRM/enums" "SCRM/models" "fmt" "strings" "time" "github.com/astaxie/beego" "SCRM/service" "SCRM/utils" "encoding/base64" "encoding/json" "encoding/xml" "strconv" "SCRM/service/org_service" "SCRM/service/wechat_service" "io/ioutil" crypter "github.com/heroicyang/wechat-crypter" ) //OpenWechatAPIController 微信开放平台相关 type OpenWechatAPIController struct { base_ctl.BaseAPIController } func (c *OpenWechatAPIController) Prepare() { c.EnableXSRF = false } //OpenWechatCtlRegistRouters 微信开放平台注册路由 func OpenWechatCtlRegistRouters() { beego.Router("/openwechat/authorizationevents", &OpenWechatAPIController{}, "*:AuthorizationEvents") beego.Router("/openwechat/mp/notice/:appid", &OpenWechatAPIController{}, "Post:MpWechatNotice") beego.Router("/openwechat/mp/authorization", &OpenWechatAPIController{}, "Get:Authorization") beego.Router("/openwechat/mp/authorizerinfo/:id/:vtime/:vcode", &OpenWechatAPIController{}, "*:AuthorizerInfo") } // AuthorizationEvents 接收微信服务器推送的 授权事件 // 有四个处理功能,由解密后的infoType决定 // 每隔10分钟定时推送 component_verify_ticket // 公众号授权给第三方平台 authorized // 公众号对第三方平台取消授权 unauthorized // 公众号对第三方平台更新授权 updateauthorized func (c *OpenWechatAPIController) AuthorizationEvents() { //接收微信服务器主动调起授权事件接收URL时,由微信服务器额外拼接在URL的几个参数, // nonce := c.GetString("nonce") // encryptType := c.GetString("encrypt_type") // msgSignature := c.GetString("msg_signature") // signature := c.GetString("signature") // timestamp := c.GetString("timestamp") // MsgEncrypt 类型的me,MsgEncrypt是根据接下来要读取的xml数据格式定义的struct, var me wechat_service.MsgEncrypt err := xml.Unmarshal(c.Ctx.Input.RequestBody, &me) if err != nil { utils.ErrorLog("read body error: %s", err) c.Ctx.WriteString("success") return } msgCrypter, _ := crypter.NewMessageCrypter(beego.AppConfig.String("openwechattoken"), beego.AppConfig.String("openwechatencodingaeskey"), beego.AppConfig.String("openwechatappid")) //这是github.com/heroicyang/config.WECHAT-crypter上的组件 msgDecrypt, _, err := msgCrypter.Decrypt(me.Encrypt) if err != nil { utils.ErrorLog("msgDecrypt error: %s", err) c.Ctx.WriteString("success") return } fmt.Println("msgDecrypt:", string(msgDecrypt)) //将上面解密后的xml读到InfoType struct var requestBody wechat_service.ComponentRequestBody err = xml.Unmarshal(msgDecrypt, &requestBody) if err != nil { utils.ErrorLog("Unmarshal ComponentRequestBody error: %s", err) c.Ctx.WriteString("success") return } //判断推送类型 // 推送 component_verify_ticket // 公众号授权给第三方平台 authorized // 公众号对第三方平台取消授权 unauthorized // 公众号对第三方平台更新授权 updateauthorized if requestBody.InfoType == "component_verify_ticket" { utils.InfoLog("接收到component_verify_ticket:%s, ", requestBody.ComponentVerifyTicket) redisClient := service.RedisClient() defer redisClient.Close() err = redisClient.Set("sgj_patient:ComponentVerifyTicket", requestBody.ComponentVerifyTicket, 0).Err() if err != nil { utils.ErrorLog("redis set failed: %s", err) } componentID, err := beego.AppConfig.Int64("openwechatcomponentid") if err != nil { utils.ErrorLog("get component id failed: %s", err) } err = wechat_service.SaveWechatComponentVerifyTicket(componentID, requestBody.ComponentVerifyTicket) if err != nil { utils.ErrorLog("SaveWechatComponentVerifyTicket failed: %s", err) } } else if requestBody.InfoType == "authorized" { utils.InfoLog("authorized: %s", requestBody.AuthorizerAppid) } else if requestBody.InfoType == "unauthorized" { utils.InfoLog("unauthorized: %s", requestBody.AuthorizerAppid) err = wechat_service.SaveAuthorizerStatusByAppID(requestBody.AuthorizerAppid, 2) if err != nil { utils.ErrorLog("SaveAuthorizerStatus failed: %s", err) } } else if requestBody.InfoType == "updateauthorized" || requestBody.InfoType == "authorized" { utils.InfoLog("%s: %s", requestBody.AuthorizerAppid, requestBody.InfoType) } else { utils.ErrorLog("Unkown infotype") c.Ctx.WriteString("success") return } c.Ctx.WriteString("success") } //MpWechatNotice 授权后公众号消息与事件接收URL func (c *OpenWechatAPIController) MpWechatNotice() { appid := c.Ctx.Input.Param(":appid") if len(appid) == 0 { utils.ErrorLog("appid not found") c.Ctx.WriteString("success") return } authorizer, err := wechat_service.GetAuthorizationByOnlyAppID(appid) if err != nil { utils.ErrorLog("Get MP Info error: %s", err) c.Ctx.WriteString("success") return } if authorizer == nil { utils.ErrorLog("Get MP Info error: 信息不存在") c.Ctx.WriteString("success") return } orgID := authorizer.UserOrgId timestamp := c.GetString("timestamp") nonce := c.GetString("nonce") // openid := c.GetString("openid") // encryptType := c.GetString("encrypt_type") msgSignature := c.GetString("msg_signature") // signature := c.GetString("signature") r := c.Ctx.Request body, err := ioutil.ReadAll(r.Body) if err != nil { utils.ErrorLog("read body error: %s", err) c.Ctx.WriteString("success") return } encryptRequestBody := &wechat_service.EncryptRequestBody{} err = xml.Unmarshal(body, encryptRequestBody) if err != nil { utils.ErrorLog("Unmarshal body error: %s", err) c.Ctx.WriteString("success") return } // Validate mstBody signature if !wechat_service.ValidateMsg(timestamp, nonce, encryptRequestBody.Encrypt, msgSignature) { fmt.Println("aa") c.Ctx.WriteString("success") return } // Decode base64 cipherData, err := base64.StdEncoding.DecodeString(encryptRequestBody.Encrypt) if err != nil { c.Ctx.WriteString("success") return } // AES Decrypt plainData, err := wechat_service.AesDecrypt(cipherData, wechat_service.AesKey) if err != nil { utils.ErrorLog("AesDecrypt error: %s", err) c.Ctx.WriteString("success") return } //封装struct textRequestBody, err := wechat_service.ParseEncryptTextRequestBody(plainData) if err != nil { c.Ctx.WriteString("success") return } fmt.Println(textRequestBody) tp := textRequestBody.MsgType FromUserName := textRequestBody.ToUserName ToUserName := textRequestBody.FromUserName if tp == "text" { //当用户向微信公众号发送消息时,回复ta wechat_service.SendMsgTypeTextMessage(appid, ToUserName, FromUserName, textRequestBody.Content, nonce, timestamp, c.Ctx, orgID) return } if tp == "event" { eventType := textRequestBody.Event if eventType == "subscribe" { //当用户关注微信公众号,回复ta wechat_service.SendSubscribeTextMessage(appid, ToUserName, FromUserName, nonce, timestamp, c.Ctx, orgID) return } if eventType == "CLICK" { //当用户点击click类型的菜单,回复ta wechat_service.SendClickButtonMessage(appid, ToUserName, FromUserName, textRequestBody.EventKey, nonce, timestamp, c.Ctx, orgID) return } if eventType == "unsubscribe" { org_service.SetFansUnsubscribe(orgID, ToUserName) } //某个类型的消息暂时后台不作处理,也需要向微信服务器做出响应 c.Ctx.WriteString("success") return } c.Ctx.WriteString("success") } func (c *OpenWechatAPIController) Authorization() { id, _ := c.GetInt64("id", 0) if id <= 0 { c.Ctx.WriteString("没有选择授权对象") return } vtime, _ := c.GetInt64("vtime", 0) if vtime <= 0 { c.Ctx.WriteString("缺少vtime参数") return } vcode := c.GetString("vcode") if len(vcode) == 0 { c.Ctx.WriteString("缺少vtime参数") return } vtime, tcode := utils.GetOrgIdCode(id, vtime) if tcode != vcode { c.Ctx.WriteString("无效的vcode") return } code, err := wechat_service.GetReqPreAuthCode() fmt.Println("code是什么", code, "错误", err) if err != nil { c.ServeFailJsonSend(enums.ErrorCodeDataException, "获取授权URL失败:("+err.Error()+")") return } uri := fmt.Sprintf(beego.AppConfig.String("httpdomain")+"/openwechat/mp/authorizerinfo/%d/%d/%s", id, vtime, vcode) url := "https://mp.weixin.qq.com/safe/bindcomponent?action=bindcomponent&auth_type=1&no_scan=1&component_appid=" + beego.AppConfig.String("openwechatappid") + "&pre_auth_code=" + code + "&redirect_uri=" + uri + "&auth_type=1#wechat_redirect" fmt.Println("url是设么东西", url) c.Data["url"] = url c.TplName = "openwechat/authorization.html" } //AuthorizerInfo 拉取公众号授权信息和基本信息 func (c *OpenWechatAPIController) AuthorizerInfo() { idS := c.Ctx.Input.Param(":id") vtimeS := c.Ctx.Input.Param(":vtime") vcode := c.Ctx.Input.Param(":vcode") id, err := strconv.ParseInt(idS, 10, 64) if err != nil { c.Data["msg"] = err.Error() c.TplName = "openwechat/errorauth.html" return } vtime, err := strconv.ParseInt(vtimeS, 10, 64) if err != nil { c.Data["msg"] = err.Error() c.TplName = "openwechat/errorauth.html" return } vtime, tcode := utils.GetOrgIdCode(id, vtime) if tcode != vcode { c.Data["msg"] = "无效的vcode" c.TplName = "openwechat/errorauth.html" return } authorizationCode := c.GetString("auth_code") redisClient := service.RedisClient() componentAccessToken, err := redisClient.Get("sgj_patient:component_access_token").Result() if err != nil { c.Data["msg"] = "需要component_access_token才能验证信息" c.TplName = "openwechat/errorauth.html" return } body, err := wechat_service.ComponentAPIQueryAuth(authorizationCode, componentAccessToken) if err != nil { c.Data["msg"] = "获取公众号授权信息失败" c.TplName = "openwechat/errorauth.html" return } var ai wechat_service.AuthorizationInfo err = json.Unmarshal([]byte(body), &ai) if err != nil { c.Data["msg"] = "解析公众号授权信息失败" c.TplName = "openwechat/errorauth.html" return } body, err = wechat_service.ComponentAPIGetAuthorizerInfo(ai.AuthorizationInfo.AuthorizerAppid, componentAccessToken) if err != nil { c.Data["msg"] = "获取公众号信息失败" c.TplName = "openwechat/errorauth.html" return } var aui wechat_service.AuthorizerInfo err = json.Unmarshal([]byte(body), &aui) if err != nil { c.Data["msg"] = "解析公众号信息失败" c.TplName = "openwechat/errorauth.html" return } var funcInfoItem []string for _, valjue := range ai.AuthorizationInfo.FuncInfo { funcInfoItem = append(funcInfoItem, strconv.FormatInt(valjue.FuncscopeCategory.ID, 10)) } BusinessInfo, err := json.MarshalIndent(aui.AuthorizerInfo.BusinessInfo, "", " ") //用json,功能的开通状况(0代表未开通,1代表已开通): open_store:是否开通微信门店功能 open_scan:是否开通微信扫商品功能 open_pay:是否开通微信支付功能 open_card:是否开通微信卡券功能 open_shake:是否开通微信摇一摇功能 if err != nil { c.Data["msg"] = "解析公众号功能的开通状况失败" c.TplName = "openwechat/errorauth.html" return } authorizationsInfo, err := wechat_service.GetAuthorizationByOrgID(id) if err != nil { c.Data["msg"] = "读取公众号信息失败" c.TplName = "openwechat/errorauth.html" return } var authorizations models.PatientAuthorizations if authorizationsInfo == nil { authorizations.UserOrgId = id authorizations.CreatedTime = time.Now().Unix() } else { authorizations = *authorizationsInfo } authorizations.UpdatedTime = time.Now().Unix() authorizations.AuthorizerAccessToken = ai.AuthorizationInfo.AuthorizerAccessToken authorizations.AuthorizerRefreshToken = ai.AuthorizationInfo.AuthorizerRefreshToken authorizations.AuthorizerFuncscopeCategory = strings.Join(funcInfoItem, ",") authorizations.AuthorizerAppid = ai.AuthorizationInfo.AuthorizerAppid authorizations.AuthorizerNickName = aui.AuthorizerInfo.NickName authorizations.AuthorizerHeadImg = aui.AuthorizerInfo.HeadImg authorizations.AuthorizerServiceTypeInfo = aui.AuthorizerInfo.ServiceTypeInfo.ID authorizations.AuthorizerVerifyTypeInfo = aui.AuthorizerInfo.VerifyTypeInfo.ID authorizations.AuthorizerUserName = aui.AuthorizerInfo.UserName authorizations.AuthorizerPrincipalName = aui.AuthorizerInfo.PrincipalName authorizations.AuthorizerBusinessInfo = string(BusinessInfo) authorizations.AuthorizerQrcodeUrl = aui.AuthorizerInfo.QrcodeURL authorizations.AuthorizerStatus = 1 err = wechat_service.SaveAuthorizationInfo(&authorizations) if err != nil { c.Data["msg"] = "保存公众号信息失败" c.TplName = "openwechat/errorauth.html" return } c.TplName = "openwechat/successauth.html" return }