scrm-go

open_wechat_controller.go 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396
  1. package global
  2. import (
  3. base_ctl "SCRM/controllers"
  4. "SCRM/enums"
  5. "SCRM/models"
  6. "fmt"
  7. "strings"
  8. "time"
  9. "github.com/astaxie/beego"
  10. "SCRM/service"
  11. "SCRM/utils"
  12. "encoding/base64"
  13. "encoding/json"
  14. "encoding/xml"
  15. "strconv"
  16. "SCRM/service/org_service"
  17. "SCRM/service/wechat_service"
  18. "io/ioutil"
  19. crypter "github.com/heroicyang/wechat-crypter"
  20. )
  21. //OpenWechatAPIController 微信开放平台相关
  22. type OpenWechatAPIController struct {
  23. base_ctl.BaseAPIController
  24. }
  25. func (c *OpenWechatAPIController) Prepare() {
  26. c.EnableXSRF = false
  27. }
  28. //OpenWechatCtlRegistRouters 微信开放平台注册路由
  29. func OpenWechatCtlRegistRouters() {
  30. beego.Router("/openwechat/authorizationevents", &OpenWechatAPIController{}, "*:AuthorizationEvents")
  31. beego.Router("/openwechat/mp/notice", &OpenWechatAPIController{}, "Post:MpWechatNotice")
  32. beego.Router("/openwechat/mp/authorization", &OpenWechatAPIController{}, "Get:Authorization")
  33. beego.Router("/openwechat/mp/authorizerinfo/:id/:vtime/:vcode", &OpenWechatAPIController{}, "*:AuthorizerInfo")
  34. }
  35. // AuthorizationEvents 接收微信服务器推送的 授权事件
  36. // 有四个处理功能,由解密后的infoType决定
  37. // 每隔10分钟定时推送 component_verify_ticket
  38. // 公众号授权给第三方平台 authorized
  39. // 公众号对第三方平台取消授权 unauthorized
  40. // 公众号对第三方平台更新授权 updateauthorized
  41. func (c *OpenWechatAPIController) AuthorizationEvents() {
  42. //接收微信服务器主动调起授权事件接收URL时,由微信服务器额外拼接在URL的几个参数,
  43. // nonce := c.GetString("nonce")
  44. // encryptType := c.GetString("encrypt_type")
  45. // msgSignature := c.GetString("msg_signature")
  46. // signature := c.GetString("signature")
  47. // timestamp := c.GetString("timestamp")
  48. // MsgEncrypt 类型的me,MsgEncrypt是根据接下来要读取的xml数据格式定义的struct,
  49. var me wechat_service.MsgEncrypt
  50. err := xml.Unmarshal(c.Ctx.Input.RequestBody, &me)
  51. if err != nil {
  52. utils.ErrorLog("read body error: %s", err)
  53. c.Ctx.WriteString("success")
  54. return
  55. }
  56. msgCrypter, _ := crypter.NewMessageCrypter(beego.AppConfig.String("openwechattoken"), beego.AppConfig.String("openwechatencodingaeskey"), beego.AppConfig.String("openwechatappid")) //这是github.com/heroicyang/config.WECHAT-crypter上的组件
  57. msgDecrypt, _, err := msgCrypter.Decrypt(me.Encrypt)
  58. if err != nil {
  59. utils.ErrorLog("msgDecrypt error: %s", err)
  60. c.Ctx.WriteString("success")
  61. return
  62. }
  63. fmt.Println("msgDecrypt:", string(msgDecrypt))
  64. //将上面解密后的xml读到InfoType struct
  65. var requestBody wechat_service.ComponentRequestBody
  66. err = xml.Unmarshal(msgDecrypt, &requestBody)
  67. if err != nil {
  68. utils.ErrorLog("Unmarshal ComponentRequestBody error: %s", err)
  69. c.Ctx.WriteString("success")
  70. return
  71. }
  72. //判断推送类型
  73. // 推送 component_verify_ticket
  74. // 公众号授权给第三方平台 authorized
  75. // 公众号对第三方平台取消授权 unauthorized
  76. // 公众号对第三方平台更新授权 updateauthorized
  77. if requestBody.InfoType == "component_verify_ticket" {
  78. utils.InfoLog("接收到component_verify_ticket:%s, ", requestBody.ComponentVerifyTicket)
  79. redisClient := service.RedisClient()
  80. defer redisClient.Close()
  81. err = redisClient.Set("sgj_patient:ComponentVerifyTicket", requestBody.ComponentVerifyTicket, 0).Err()
  82. if err != nil {
  83. utils.ErrorLog("redis set failed: %s", err)
  84. }
  85. componentID, err := beego.AppConfig.Int64("openwechatcomponentid")
  86. if err != nil {
  87. utils.ErrorLog("get component id failed: %s", err)
  88. }
  89. err = wechat_service.SaveWechatComponentVerifyTicket(componentID, requestBody.ComponentVerifyTicket)
  90. if err != nil {
  91. utils.ErrorLog("SaveWechatComponentVerifyTicket failed: %s", err)
  92. }
  93. } else if requestBody.InfoType == "authorized" {
  94. utils.InfoLog("authorized: %s", requestBody.AuthorizerAppid)
  95. } else if requestBody.InfoType == "unauthorized" {
  96. utils.InfoLog("unauthorized: %s", requestBody.AuthorizerAppid)
  97. err = wechat_service.SaveAuthorizerStatusByAppID(requestBody.AuthorizerAppid, 2)
  98. if err != nil {
  99. utils.ErrorLog("SaveAuthorizerStatus failed: %s", err)
  100. }
  101. } else if requestBody.InfoType == "updateauthorized" || requestBody.InfoType == "authorized" {
  102. utils.InfoLog("%s: %s", requestBody.AuthorizerAppid, requestBody.InfoType)
  103. } else {
  104. utils.ErrorLog("Unkown infotype")
  105. c.Ctx.WriteString("success")
  106. return
  107. }
  108. c.Ctx.WriteString("success")
  109. }
  110. //MpWechatNotice 授权后公众号消息与事件接收URL
  111. func (c *OpenWechatAPIController) MpWechatNotice() {
  112. appid := c.GetString("appid")
  113. if len(appid) == 0 {
  114. utils.ErrorLog("appid not found")
  115. c.Ctx.WriteString("success")
  116. return
  117. }
  118. authorizer, err := wechat_service.GetAuthorizationByOnlyAppID(appid)
  119. if err != nil {
  120. utils.ErrorLog("Get MP Info error: %s", err)
  121. c.Ctx.WriteString("success")
  122. return
  123. }
  124. if authorizer == nil {
  125. utils.ErrorLog("Get MP Info error: 信息不存在")
  126. c.Ctx.WriteString("success")
  127. return
  128. }
  129. orgID := authorizer.UserOrgId
  130. timestamp := c.GetString("timestamp")
  131. nonce := c.GetString("nonce")
  132. // openid := c.GetString("openid")
  133. // encryptType := c.GetString("encrypt_type")
  134. msgSignature := c.GetString("msg_signature")
  135. // signature := c.GetString("signature")
  136. r := c.Ctx.Request
  137. body, err := ioutil.ReadAll(r.Body)
  138. if err != nil {
  139. utils.ErrorLog("read body error: %s", err)
  140. c.Ctx.WriteString("success")
  141. return
  142. }
  143. encryptRequestBody := &wechat_service.EncryptRequestBody{}
  144. err = xml.Unmarshal(body, encryptRequestBody)
  145. if err != nil {
  146. utils.ErrorLog("Unmarshal body error: %s", err)
  147. c.Ctx.WriteString("success")
  148. return
  149. }
  150. // Validate mstBody signature
  151. if !wechat_service.ValidateMsg(timestamp, nonce, encryptRequestBody.Encrypt, msgSignature) {
  152. fmt.Println("aa")
  153. c.Ctx.WriteString("success")
  154. return
  155. }
  156. // Decode base64
  157. cipherData, err := base64.StdEncoding.DecodeString(encryptRequestBody.Encrypt)
  158. if err != nil {
  159. c.Ctx.WriteString("success")
  160. return
  161. }
  162. // AES Decrypt
  163. plainData, err := wechat_service.AesDecrypt(cipherData, wechat_service.AesKey)
  164. if err != nil {
  165. utils.ErrorLog("AesDecrypt error: %s", err)
  166. c.Ctx.WriteString("success")
  167. return
  168. }
  169. //封装struct
  170. textRequestBody, err := wechat_service.ParseEncryptTextRequestBody(plainData)
  171. if err != nil {
  172. c.Ctx.WriteString("success")
  173. return
  174. }
  175. fmt.Println(textRequestBody)
  176. tp := textRequestBody.MsgType
  177. FromUserName := textRequestBody.ToUserName
  178. ToUserName := textRequestBody.FromUserName
  179. if tp == "text" {
  180. //当用户向微信公众号发送消息时,回复ta
  181. wechat_service.SendMsgTypeTextMessage(appid, ToUserName, FromUserName, textRequestBody.Content, nonce, timestamp, c.Ctx, orgID)
  182. return
  183. }
  184. if tp == "event" {
  185. eventType := textRequestBody.Event
  186. if eventType == "subscribe" {
  187. //当用户关注微信公众号,回复ta
  188. wechat_service.SendSubscribeTextMessage(appid, ToUserName, FromUserName, nonce, timestamp, c.Ctx, orgID)
  189. return
  190. }
  191. if eventType == "CLICK" {
  192. //当用户点击click类型的菜单,回复ta
  193. wechat_service.SendClickButtonMessage(appid, ToUserName, FromUserName, textRequestBody.EventKey, nonce, timestamp, c.Ctx, orgID)
  194. return
  195. }
  196. if eventType == "unsubscribe" {
  197. org_service.SetFansUnsubscribe(orgID, ToUserName)
  198. }
  199. //某个类型的消息暂时后台不作处理,也需要向微信服务器做出响应
  200. c.Ctx.WriteString("success")
  201. return
  202. }
  203. c.Ctx.WriteString("success")
  204. }
  205. func (c *OpenWechatAPIController) Authorization() {
  206. id, _ := c.GetInt64("id", 0)
  207. if id <= 0 {
  208. c.Ctx.WriteString("没有选择授权对象")
  209. return
  210. }
  211. vtime, _ := c.GetInt64("vtime", 0)
  212. if vtime <= 0 {
  213. c.Ctx.WriteString("缺少vtime参数")
  214. return
  215. }
  216. vcode := c.GetString("vcode")
  217. if len(vcode) == 0 {
  218. c.Ctx.WriteString("缺少vtime参数")
  219. return
  220. }
  221. vtime, tcode := utils.GetOrgIdCode(id, vtime)
  222. if tcode != vcode {
  223. c.Ctx.WriteString("无效的vcode")
  224. return
  225. }
  226. code, err := wechat_service.GetReqPreAuthCode()
  227. if err != nil {
  228. c.ServeFailJsonSend(enums.ErrorCodeDataException, "获取授权URL失败:("+err.Error()+")")
  229. return
  230. }
  231. uri := fmt.Sprintf(beego.AppConfig.String("httpdomain")+"/openwechat/mp/authorizerinfo/%d/%d/%s", id, vtime, vcode)
  232. 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"
  233. c.Data["url"] = url
  234. c.TplName = "openwechat/authorization.html"
  235. }
  236. //AuthorizerInfo 拉取公众号授权信息和基本信息
  237. func (c *OpenWechatAPIController) AuthorizerInfo() {
  238. idS := c.Ctx.Input.Param(":id")
  239. vtimeS := c.Ctx.Input.Param(":vtime")
  240. vcode := c.Ctx.Input.Param(":vcode")
  241. id, err := strconv.ParseInt(idS, 10, 64)
  242. if err != nil {
  243. c.Data["msg"] = err.Error()
  244. c.TplName = "openwechat/errorauth.html"
  245. return
  246. }
  247. vtime, err := strconv.ParseInt(vtimeS, 10, 64)
  248. if err != nil {
  249. c.Data["msg"] = err.Error()
  250. c.TplName = "openwechat/errorauth.html"
  251. return
  252. }
  253. vtime, tcode := utils.GetOrgIdCode(id, vtime)
  254. if tcode != vcode {
  255. c.Data["msg"] = "无效的vcode"
  256. c.TplName = "openwechat/errorauth.html"
  257. return
  258. }
  259. authorizationCode := c.GetString("auth_code")
  260. redisClient := service.RedisClient()
  261. componentAccessToken, err := redisClient.Get("sgj_patient:component_access_token").Result()
  262. if err != nil {
  263. c.Data["msg"] = "需要component_access_token才能验证信息"
  264. c.TplName = "openwechat/errorauth.html"
  265. return
  266. }
  267. body, err := wechat_service.ComponentAPIQueryAuth(authorizationCode, componentAccessToken)
  268. if err != nil {
  269. c.Data["msg"] = "获取公众号授权信息失败"
  270. c.TplName = "openwechat/errorauth.html"
  271. return
  272. }
  273. var ai wechat_service.AuthorizationInfo
  274. err = json.Unmarshal([]byte(body), &ai)
  275. if err != nil {
  276. c.Data["msg"] = "解析公众号授权信息失败"
  277. c.TplName = "openwechat/errorauth.html"
  278. return
  279. }
  280. body, err = wechat_service.ComponentAPIGetAuthorizerInfo(ai.AuthorizationInfo.AuthorizerAppid, componentAccessToken)
  281. if err != nil {
  282. c.Data["msg"] = "获取公众号信息失败"
  283. c.TplName = "openwechat/errorauth.html"
  284. return
  285. }
  286. var aui wechat_service.AuthorizerInfo
  287. err = json.Unmarshal([]byte(body), &aui)
  288. if err != nil {
  289. c.Data["msg"] = "解析公众号信息失败"
  290. c.TplName = "openwechat/errorauth.html"
  291. return
  292. }
  293. var funcInfoItem []string
  294. for _, valjue := range ai.AuthorizationInfo.FuncInfo {
  295. funcInfoItem = append(funcInfoItem, strconv.FormatInt(valjue.FuncscopeCategory.ID, 10))
  296. }
  297. BusinessInfo, err := json.MarshalIndent(aui.AuthorizerInfo.BusinessInfo, "", " ")
  298. //用json,功能的开通状况(0代表未开通,1代表已开通): open_store:是否开通微信门店功能 open_scan:是否开通微信扫商品功能 open_pay:是否开通微信支付功能 open_card:是否开通微信卡券功能 open_shake:是否开通微信摇一摇功能
  299. if err != nil {
  300. c.Data["msg"] = "解析公众号功能的开通状况失败"
  301. c.TplName = "openwechat/errorauth.html"
  302. return
  303. }
  304. authorizationsInfo, err := wechat_service.GetAuthorizationByOrgID(id)
  305. if err != nil {
  306. c.Data["msg"] = "读取公众号信息失败"
  307. c.TplName = "openwechat/errorauth.html"
  308. return
  309. }
  310. var authorizations models.PatientAuthorizations
  311. if authorizationsInfo == nil {
  312. authorizations.UserOrgId = id
  313. authorizations.CreatedTime = time.Now().Unix()
  314. } else {
  315. authorizations = *authorizationsInfo
  316. }
  317. authorizations.UpdatedTime = time.Now().Unix()
  318. authorizations.AuthorizerAccessToken = ai.AuthorizationInfo.AuthorizerAccessToken
  319. authorizations.AuthorizerRefreshToken = ai.AuthorizationInfo.AuthorizerRefreshToken
  320. authorizations.AuthorizerFuncscopeCategory = strings.Join(funcInfoItem, ",")
  321. authorizations.AuthorizerAppid = ai.AuthorizationInfo.AuthorizerAppid
  322. authorizations.AuthorizerNickName = aui.AuthorizerInfo.NickName
  323. authorizations.AuthorizerHeadImg = aui.AuthorizerInfo.HeadImg
  324. authorizations.AuthorizerServiceTypeInfo = aui.AuthorizerInfo.ServiceTypeInfo.ID
  325. authorizations.AuthorizerVerifyTypeInfo = aui.AuthorizerInfo.VerifyTypeInfo.ID
  326. authorizations.AuthorizerUserName = aui.AuthorizerInfo.UserName
  327. authorizations.AuthorizerPrincipalName = aui.AuthorizerInfo.PrincipalName
  328. authorizations.AuthorizerBusinessInfo = string(BusinessInfo)
  329. authorizations.AuthorizerQrcodeUrl = aui.AuthorizerInfo.QrcodeURL
  330. authorizations.AuthorizerStatus = 1
  331. err = wechat_service.SaveAuthorizationInfo(&authorizations)
  332. if err != nil {
  333. c.Data["msg"] = "保存公众号信息失败"
  334. c.TplName = "openwechat/errorauth.html"
  335. return
  336. }
  337. c.TplName = "openwechat/successauth.html"
  338. return
  339. }