diff --git a/platform-services/wx-mp-service/src/main/java/cn/skcks/docking/wx/services/mp/controller/MpAppController.java b/platform-services/wx-mp-service/src/main/java/cn/skcks/docking/wx/services/mp/controller/MpAppController.java index 8b4b9bb..53256bb 100644 --- a/platform-services/wx-mp-service/src/main/java/cn/skcks/docking/wx/services/mp/controller/MpAppController.java +++ b/platform-services/wx-mp-service/src/main/java/cn/skcks/docking/wx/services/mp/controller/MpAppController.java @@ -5,16 +5,19 @@ import cn.skcks.docking.wx.common.json.JsonResponse; import cn.skcks.docking.wx.common.page.PageWrapper; import cn.skcks.docking.wx.orm.entity.MpApp; import cn.skcks.docking.wx.services.mp.service.MpAppService; +import cn.skcks.docking.wx.services.mp.vo.verify.SignatureVo; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.Parameters; import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import lombok.RequiredArgsConstructor; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; +import org.springdoc.core.annotations.ParameterObject; +import org.springframework.web.bind.annotation.*; +import java.io.IOException; import java.util.List; @Tag(name = "微信公众号") @@ -41,4 +44,10 @@ public class MpAppController { public JsonResponse> getMpAppListPage(@RequestParam Integer pageNo, @RequestParam Integer pageSize) { return JsonResponse.success(mpAppService.getMpAppPageList(pageNo,pageSize)); } + + @RequestMapping("/{appId}") + public void verify(HttpServletRequest request, HttpServletResponse response, + @PathVariable String appId, @ParameterObject SignatureVo signatureVo) throws Exception { + mpAppService.service(request, response, appId, signatureVo); + } } diff --git a/platform-services/wx-mp-service/src/main/java/cn/skcks/docking/wx/services/mp/service/MpAppService.java b/platform-services/wx-mp-service/src/main/java/cn/skcks/docking/wx/services/mp/service/MpAppService.java index 3155d99..cdcb8e6 100644 --- a/platform-services/wx-mp-service/src/main/java/cn/skcks/docking/wx/services/mp/service/MpAppService.java +++ b/platform-services/wx-mp-service/src/main/java/cn/skcks/docking/wx/services/mp/service/MpAppService.java @@ -1,14 +1,31 @@ package cn.skcks.docking.wx.services.mp.service; +import cn.hutool.core.date.DateUtil; import cn.skcks.docking.wx.common.page.PageWrapper; import cn.skcks.docking.wx.orm.entity.MpApp; import cn.skcks.docking.wx.orm.mapper.MpAppMapper; +import cn.skcks.docking.wx.services.mp.vo.verify.SignatureVo; +import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import io.micrometer.common.util.StringUtils; +import jakarta.annotation.PostConstruct; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl; +import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; +import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage; +import me.chanjar.weixin.mp.config.impl.WxMpDefaultConfigImpl; +import org.apache.commons.lang3.ObjectUtils; import org.springframework.stereotype.Service; +import java.io.IOException; import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ForkJoinPool; @Slf4j @Service @@ -16,6 +33,96 @@ import java.util.List; public class MpAppService { private final MpAppMapper mpAppMapper; + private final Map serviceMap = new ConcurrentHashMap<>(); + + @PostConstruct + private void init(){ + LambdaQueryChainWrapper queryWrapper = new LambdaQueryChainWrapper<>(mpAppMapper); + queryWrapper.ne(MpApp::getEnable, false); + List mpApps = queryWrapper.list(); + + new ForkJoinPool(Runtime.getRuntime().availableProcessors()).execute(() -> { + mpApps.parallelStream().forEach(mpApp -> { + WxMpDefaultConfigImpl config = new WxMpDefaultConfigImpl(); + config.setAppId(mpApp.getAppId()); + config.setSecret(mpApp.getAppSecret()); + config.setToken(mpApp.getToken()); + config.setAesKey(mpApp.getEncodingAesKey()); + + WxMpService service = new WxMpServiceImpl(); + service.setWxMpConfigStorage(config); + + serviceMap.put(mpApp.getAppId(), service); + }); + }); + } + + public void service(HttpServletRequest request, HttpServletResponse response, String appId, SignatureVo signatureVo) throws IOException { + response.setContentType("text/html;charset=utf-8"); + response.setStatus(HttpServletResponse.SC_OK); + + WxMpService wxMpService = serviceMap.get(appId); + if(ObjectUtils.anyNull(appId, signatureVo, wxMpService)){ + response.getWriter().println("非法请求"); + return; + } + + if(!wxMpService.checkSignature(signatureVo.getTimestamp(), signatureVo.getNonce(), signatureVo.getSignature())){ + response.getWriter().println("非法请求"); + return; + } + + + // 签名验证请求 + String echostr = request.getParameter("echostr"); + if(StringUtils.isNotBlank(echostr)){ + response.getWriter().println(echostr); + return; + } + + String encryptType = StringUtils.isBlank(request.getParameter("encrypt_type")) ? + "raw" : + request.getParameter("encrypt_type"); + + if ("raw".equals(encryptType)) { + // 明文传输的消息 + WxMpXmlMessage inMessage = WxMpXmlMessage.fromXml(request.getInputStream()); + // WxMpXmlOutMessage outMessage = wxMpMessageRouter.route(inMessage); + // if(outMessage == null) { + // //为null,说明路由配置有问题,需要注意 + // response.getWriter().write(""); + // } + // response.getWriter().write(outMessage.toXml()); + + log.debug("\n[↓] 接收消息: \n{}", inMessage); + + WxMpXmlOutMessage outMessage = WxMpXmlOutMessage.TEXT() + .toUser(inMessage.getFromUser()) + .fromUser(inMessage.getToUser()) + .content(DateUtil.now()) + .build(); + + log.debug("\n[↑] 响应消息: \n{}", outMessage); + response.getWriter().write(outMessage.toXml()); + return; + } + + // if ("aes".equals(encryptType)) { + // // 是aes加密的消息 + // String msgSignature = request.getParameter("msg_signature"); + // WxMpXmlMessage inMessage = WxMpXmlMessage.fromEncryptedXml(request.getInputStream(), wxMpConfigStorage, timestamp, nonce, msgSignature); + // WxMpXmlOutMessage outMessage = wxMpMessageRouter.route(inMessage); + // if(outMessage == null) { + // //为null,说明路由配置有问题,需要注意 + // response.getWriter().write(""); + // } + // response.getWriter().write(outMessage.toEncryptedXml(wxMpConfigStorage)); + // return; + // } + + response.getWriter().println("不可识别的加密类型"); + // return; + } /** * 获取所有公众号列表 diff --git a/platform-services/wx-mp-service/src/main/java/cn/skcks/docking/wx/services/mp/vo/verify/SignatureVo.java b/platform-services/wx-mp-service/src/main/java/cn/skcks/docking/wx/services/mp/vo/verify/SignatureVo.java new file mode 100644 index 0000000..64cae26 --- /dev/null +++ b/platform-services/wx-mp-service/src/main/java/cn/skcks/docking/wx/services/mp/vo/verify/SignatureVo.java @@ -0,0 +1,15 @@ +package cn.skcks.docking.wx.services.mp.vo.verify; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Data +@Schema(title="签名验证 Vo") +public class SignatureVo { + @Schema(description = "时间戳") + private String timestamp; + @Schema(description = "随机数") + private String nonce; + @Schema(description = "签名") + private String signature; +} diff --git a/platform-services/wx-mp-service/src/main/resources/application.yml b/platform-services/wx-mp-service/src/main/resources/application.yml index b1d196a..a93d03a 100644 --- a/platform-services/wx-mp-service/src/main/resources/application.yml +++ b/platform-services/wx-mp-service/src/main/resources/application.yml @@ -4,3 +4,8 @@ spring: server: port: 18881 + +logging: + level: + root: info + cn.skcks.docking.wx: debug diff --git a/wx-docking-platform-common/src/main/resources/application.yml b/wx-docking-platform-common/src/main/resources/application.yml index 00ef65f..3f7182d 100644 --- a/wx-docking-platform-common/src/main/resources/application.yml +++ b/wx-docking-platform-common/src/main/resources/application.yml @@ -10,3 +10,8 @@ spring: deserialization: # 忽略没有的字段 fail_on_unknown_properties: false + +logging: + level: + root: info + cn.skcks.docking.wx: debug