WeChatEnterpriseFunctionController.java 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. package jnpf.message.controller;
  2. import cn.hutool.core.io.IoUtil;
  3. import cn.hutool.core.util.ObjectUtil;
  4. import jnpf.socials.config.CustomAuthConfig;
  5. import jnpf.socials.config.SocialsConfig;
  6. import jnpf.socials.utils.AuthSocialsUtil;
  7. import io.swagger.v3.oas.annotations.tags.Tag;
  8. import jakarta.servlet.http.HttpServletRequest;
  9. import jnpf.config.ConfigValueUtil;
  10. import jnpf.constant.GlobalConst;
  11. import jnpf.database.util.TenantDataSourceUtil;
  12. import jnpf.message.entity.AccountConfigEntity;
  13. import jnpf.message.service.AccountConfigService;
  14. import jnpf.util.*;
  15. import jnpf.util.wxutil.mp.WXGZHWebChatUtil;
  16. import jnpf.util.wxutil.mp.aes.WXBizMsgCrypt;
  17. import lombok.extern.slf4j.Slf4j;
  18. import org.springframework.beans.factory.annotation.Autowired;
  19. import org.springframework.stereotype.Controller;
  20. import org.springframework.web.bind.annotation.*;
  21. import java.io.IOException;
  22. import java.util.Map;
  23. import java.util.Objects;
  24. /**
  25. * <p>
  26. * 企业微信服务商事件处理
  27. * </p>
  28. *
  29. * @author JNPF开发平台组
  30. * @version V3.4.2
  31. * @copyright 引迈信息技术有限公司
  32. * @date 2025/6/5 15:40:14
  33. */
  34. @Tag(name = "企业微信事件处理", description = "WeChatEnterpriseOpen")
  35. @Controller
  36. @RequestMapping("/api/message/weopen")
  37. @Slf4j
  38. public class WeChatEnterpriseFunctionController {
  39. @Autowired
  40. private AccountConfigService accountConfigService;
  41. @Autowired
  42. private ConfigValueUtil configValueUtil;
  43. @Autowired
  44. private SocialsConfig socialsConfig;
  45. /**
  46. * 企业微信服务商消息接收 官网登录使用
  47. * @param request
  48. * @return
  49. * @throws Exception
  50. */
  51. @ResponseBody
  52. @NoDataSourceBind
  53. @RequestMapping(value = "/white/loginreceive", method = {RequestMethod.GET, RequestMethod.POST})
  54. public String loginreceive(HttpServletRequest request, String loginType
  55. , @RequestParam(value = "type", required = false) String type) throws Exception{
  56. //获取企业微信账号配置
  57. CustomAuthConfig config = socialsConfig.getSocialMap().get("wechat_enterprise_ww");
  58. if(config == null){
  59. log.info("未找到企业微信商户配置");
  60. return "";
  61. }
  62. String appId;
  63. String token;
  64. String encodingAesKey;
  65. if(Objects.equals("qrcode", loginType)){
  66. appId = config.getClientId();
  67. token = config.getClientToken();
  68. encodingAesKey = config.getClientEncodingAesKey();
  69. }else if(Objects.equals("web", loginType)){
  70. appId = config.getAppClientId();
  71. token = config.getAppClientToken();
  72. encodingAesKey = config.getAppClientEncodingAesKey();
  73. }else{
  74. log.info("企业微信商户配置不正确");
  75. return "";
  76. }
  77. // 回调地址检测传的都是企业ID
  78. boolean isCheckUrl = "get".equalsIgnoreCase(request.getMethod());
  79. // 数据回调接口传的是企业ID, 指令回调接口传的是APPID
  80. boolean isDataRequest = "data".equalsIgnoreCase(type);
  81. if(isCheckUrl || isDataRequest){
  82. appId = config.getCorpId();
  83. }
  84. return parseEvent(request, appId, token, encodingAesKey);
  85. }
  86. /**
  87. * 企业微信服务商消息接收
  88. * @param request
  89. * @param enCode 微信公账号账号编码
  90. * @param type 接口回调模式, commond: 指令回调, data: 数据回调(消息事件)
  91. * @param tenantId
  92. * @return
  93. * @throws Exception
  94. */
  95. @ResponseBody
  96. @NoDataSourceBind
  97. @RequestMapping(value = "/white/receive", method = {RequestMethod.GET, RequestMethod.POST})
  98. public String receive(HttpServletRequest request,
  99. @RequestParam(value = "enCode") String enCode,
  100. @RequestParam(value = "type", required = false) String type,
  101. @RequestParam(value = "tenantId", required = false) String tenantId) throws Exception{
  102. if(configValueUtil.isMultiTenancy() && StringUtil.isNotEmpty(tenantId)){
  103. TenantDataSourceUtil.switchTenant(tenantId);
  104. }
  105. //获取企业微信账号配置
  106. AccountConfigEntity accountConfigEntity = accountConfigService.getInfoByEnCode(enCode,"7");
  107. if(ObjectUtil.isEmpty(accountConfigEntity)){
  108. log.info("未找到与编码相对应的微信公众号配置");
  109. return "";
  110. }
  111. // 回调地址检测传的都是企业ID
  112. boolean isCheckUrl = "get".equalsIgnoreCase(request.getMethod());
  113. // 数据回调接口传的是企业ID, 指令回调接口传的是APPID
  114. boolean isDataRequest = "data".equalsIgnoreCase(type);
  115. String appId = isDataRequest || isCheckUrl ? accountConfigEntity.getAppKey() : accountConfigEntity.getAppId();
  116. return parseEvent(request, appId, accountConfigEntity.getAgentId(), accountConfigEntity.getBearer());
  117. }
  118. private String parseEvent(HttpServletRequest request, String appId, String token, String encodingAesKey) throws IOException {
  119. boolean isCheckUrl = "get".equalsIgnoreCase(request.getMethod());
  120. String signature = request.getParameter("signature");
  121. if(StringUtil.isEmpty(signature)){
  122. signature = XSSEscape.escape(request.getParameter("msg_signature"));
  123. }
  124. String echostr = XSSEscape.escape(request.getParameter("echostr"));
  125. if(StringUtil.isEmpty(echostr)){
  126. // isCheckUrl = false;
  127. echostr = IoUtil.read(request.getInputStream(), GlobalConst.DEFAULT_CHARSET);
  128. }
  129. String timestamp = request.getParameter("timestamp");
  130. String nonce = request.getParameter("nonce");
  131. String result;
  132. try {
  133. if (isCheckUrl) {
  134. WXBizMsgCrypt crypt = new WXBizMsgCrypt(token, encodingAesKey, appId);
  135. result = crypt.verifyUrl(signature, timestamp, nonce, echostr);
  136. if(log.isDebugEnabled()){
  137. log.debug("企业微信接口检测:{}", result);
  138. }
  139. } else {
  140. WXBizMsgCrypt crypt = new WXBizMsgCrypt(token, encodingAesKey, appId);
  141. result = crypt.decryptMsg(signature, timestamp, nonce, echostr);
  142. if(log.isDebugEnabled()){
  143. log.debug("企业微信接口消息:{}", result);
  144. }
  145. Map<String, Object> resultMap = WXGZHWebChatUtil.xmlToMap(result);
  146. result = handlerEvent(resultMap);
  147. }
  148. } catch (Exception e) {
  149. log.info("企业微信回调失败:{}", e.getMessage());
  150. result = "";
  151. }
  152. return result;
  153. }
  154. private String handlerEvent(Map<String, Object> resultMap) {
  155. String event = (String) resultMap.get("InfoType");
  156. if (Objects.equals("suite_ticket", event)) {
  157. String suitId = (String) resultMap.get("SuiteId");
  158. String suitTicket = (String) resultMap.get("SuiteTicket");
  159. AuthSocialsUtil.setSuitTicket(suitId, suitTicket);
  160. if(log.isDebugEnabled()){
  161. log.debug("服务商SuitTicket刷新: suitId:{}, suitTicket:{}", suitId, suitTicket);
  162. }
  163. }
  164. return "success";
  165. }
  166. }