Commit c671b01b0a038ac836cb71be323178d61461917d

Authored by YunaiV
1 parent 275a1b10

mp:增加公众号的校验签名回调

yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/open/MpOpenController.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mp.controller.admin.open;
  2 +
  3 +import cn.hutool.core.util.StrUtil;
  4 +import cn.iocoder.yudao.module.mp.controller.admin.open.vo.MpOpenCheckSignatureReqVO;
  5 +import cn.iocoder.yudao.module.mp.framework.mp.core.MpServiceFactory;
  6 +import io.swagger.annotations.Api;
  7 +import io.swagger.annotations.ApiOperation;
  8 +import lombok.extern.slf4j.Slf4j;
  9 +import me.chanjar.weixin.mp.api.WxMpService;
  10 +import org.springframework.validation.annotation.Validated;
  11 +import org.springframework.web.bind.annotation.*;
  12 +
  13 +import javax.annotation.Resource;
  14 +
  15 +@Api(tags = "管理后台 - 公众号回调")
  16 +@RestController
  17 +@RequestMapping("/mp/open")
  18 +@Validated
  19 +@Slf4j
  20 +public class MpOpenController {
  21 +
  22 + @Resource
  23 + private MpServiceFactory mpServiceFactory;
  24 +
  25 + @ApiOperation("校验签名") // 参见 https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Access_Overview.html 文档
  26 + @GetMapping(value = "/{appId}", produces = "text/plain;charset=utf-8")
  27 + public String checkSignature(@PathVariable("appId") String appId,
  28 + MpOpenCheckSignatureReqVO reqVO) {
  29 + log.info("[checkSignature][appId({}) 接收到来自微信服务器的认证消息({})]", appId, reqVO);
  30 + // 校验请求签名
  31 + WxMpService wxMpService = mpServiceFactory.getRequiredMpService(appId);
  32 + // 校验通过
  33 + if (wxMpService.checkSignature(reqVO.getTimestamp(), reqVO.getNonce(), reqVO.getSignature())) {
  34 + return reqVO.getEchostr();
  35 + }
  36 + // 校验不通过
  37 + return "非法请求";
  38 + }
  39 +
  40 +}
... ...
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/open/vo/MpOpenCheckSignatureReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mp.controller.admin.open.vo;
  2 +
  3 +
  4 +import io.swagger.annotations.ApiModel;
  5 +import io.swagger.annotations.ApiModelProperty;
  6 +import lombok.Data;
  7 +import lombok.EqualsAndHashCode;
  8 +import lombok.ToString;
  9 +import org.springframework.web.bind.annotation.RequestParam;
  10 +
  11 +import javax.validation.constraints.NotEmpty;
  12 +
  13 +@ApiModel("管理后台 - 公众号校验签名 Request VO")
  14 +@Data
  15 +public class MpOpenCheckSignatureReqVO {
  16 +
  17 + @ApiModelProperty(value = "微信加密签名", required = true, example = "490eb57f448b87bd5f20ccef58aa4de46aa1908e")
  18 + @NotEmpty(message = "微信加密签名不能为空")
  19 + private String signature;
  20 +
  21 + @ApiModelProperty(value = "时间戳", required = true, example = "1672587863")
  22 + @NotEmpty(message = "时间戳不能为空")
  23 + private String timestamp;
  24 +
  25 + @ApiModelProperty(value = "随机数", required = true, example = "1827365808")
  26 + @NotEmpty(message = "随机数不能为空")
  27 + private String nonce;
  28 +
  29 + @ApiModelProperty(value = "随机字符串", required = true, example = "2721154047828672511")
  30 + @NotEmpty(message = "随机字符串不能为空")
  31 + @SuppressWarnings("SpellCheckingInspection")
  32 + private String echostr;
  33 +
  34 +}
... ...
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/package-info.java 0 → 100644
  1 +/**
  2 + * 提供 RESTful API 给前端:
  3 + * 1. admin 包:提供给管理后台 yudao-ui-admin 前端项目
  4 + * 2. app 包:提供给用户 APP yudao-ui-app 前端项目,它的 Controller 和 VO 都要添加 App 前缀,用于和管理后台进行区分
  5 + */
  6 +package cn.iocoder.yudao.module.mp.controller;
... ...
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/framework/mp/core/DefaultMpServiceFactory.java
... ... @@ -94,65 +94,65 @@ public class DefaultMpServiceFactory implements MpServiceFactory {
94 94 // 第二步,创建 WxMpService 对象
95 95 WxMpService service = new WxMpServiceImpl();
96 96 service.setWxMpConfigStorage(configStorage);
97   - return null;
  97 + return service;
98 98 }
99 99  
100 100 private WxMpMessageRouter buildMpMessageRouter(WxMpService mpService) {
101   - final WxMpMessageRouter newRouter = new WxMpMessageRouter(mpService);
  101 + WxMpMessageRouter router = new WxMpMessageRouter(mpService);
102 102 // 记录所有事件的日志(异步执行)
103   - newRouter.rule().handler(logHandler).next();
  103 + router.rule().handler(logHandler).next();
104 104  
105 105 // 接收客服会话管理事件
106   - newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
  106 + router.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
107 107 .event(WxMpEventConstants.CustomerService.KF_CREATE_SESSION)
108 108 .handler(kfSessionHandler).end();
109   - newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
  109 + router.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
110 110 .event(WxMpEventConstants.CustomerService.KF_CLOSE_SESSION)
111 111 .handler(kfSessionHandler)
112 112 .end();
113   - newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
  113 + router.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
114 114 .event(WxMpEventConstants.CustomerService.KF_SWITCH_SESSION)
115 115 .handler(kfSessionHandler).end();
116 116  
117 117 // 门店审核事件
118   - newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
  118 + router.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
119 119 .event(WxMpEventConstants.POI_CHECK_NOTIFY)
120 120 .handler(storeCheckNotifyHandler).end();
121 121  
122 122 // 自定义菜单事件
123   - newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
  123 + router.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
124 124 .event(WxConsts.MenuButtonType.CLICK).handler(menuHandler).end();
125 125  
126 126 // 点击菜单连接事件
127   - newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
  127 + router.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
128 128 .event(WxConsts.MenuButtonType.VIEW).handler(nullHandler).end();
129 129  
130 130 // 关注事件
131   - newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
  131 + router.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
132 132 .event(WxConsts.EventType.SUBSCRIBE).handler(subscribeHandler)
133 133 .end();
134 134  
135 135 // 取消关注事件
136   - newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
  136 + router.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
137 137 .event(WxConsts.EventType.UNSUBSCRIBE)
138 138 .handler(unsubscribeHandler).end();
139 139  
140 140 // 上报地理位置事件
141   - newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
  141 + router.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
142 142 .event(WxConsts.EventType.LOCATION).handler(locationHandler)
143 143 .end();
144 144  
145 145 // 接收地理位置消息
146   - newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.LOCATION)
  146 + router.rule().async(false).msgType(WxConsts.XmlMsgType.LOCATION)
147 147 .handler(locationHandler).end();
148 148  
149 149 // 扫码事件
150   - newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
  150 + router.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
151 151 .event(WxConsts.EventType.SCAN).handler(scanHandler).end();
152 152  
153 153 // 默认
154   - newRouter.rule().async(false).handler(msgHandler).end();
155   - return newRouter;
  154 + router.rule().async(false).handler(msgHandler).end();
  155 + return router;
156 156 }
157 157  
158 158 }
... ...
yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/framework/mp/core/MpServiceFactory.java
1 1 package cn.iocoder.yudao.module.mp.framework.mp.core;
2 2  
  3 +import cn.hutool.core.lang.Assert;
3 4 import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO;
4 5 import me.chanjar.weixin.mp.api.WxMpMessageRouter;
5 6 import me.chanjar.weixin.mp.api.WxMpService;
... ... @@ -28,6 +29,12 @@ public interface MpServiceFactory {
28 29 */
29 30 WxMpService getMpService(String appId);
30 31  
  32 + default WxMpService getRequiredMpService(String appId) {
  33 + WxMpService wxMpService = getMpService(appId);
  34 + Assert.notNull(wxMpService, "找到对应 appId({}) 的 WxMpService,请核实!", appId);
  35 + return wxMpService;
  36 + }
  37 +
31 38 /**
32 39 * 获得 appId 对应的 WxMpMessageRouter 实例
33 40 *
... ...
yudao-server/src/main/resources/application.yaml
... ... @@ -92,6 +92,7 @@ yudao:
92 92 security:
93 93 permit-all_urls:
94 94 - /admin-ui/** # /resources/admin-ui 目录下的静态资源
  95 + - /admin-api/mp/open/** # 微信公众号开放平台,微信回调接口,不需要登录
95 96 swagger:
96 97 title: 管理后台
97 98 description: 提供管理员管理的所有功能
... ... @@ -119,6 +120,7 @@ yudao:
119 120 - /admin-api/system/sms/callback/* # 短信回调接口,无法带上租户编号
120 121 - /admin-api/pay/notify/callback/* # 支付回调通知,不携带租户编号
121 122 - /jmreport/* # 积木报表,无法携带租户编号
  123 + - /admin-api/mp/open/** # 微信公众号开放平台,微信回调接口,无法携带租户编号
122 124 ignore-tables:
123 125 - system_tenant
124 126 - system_tenant_package
... ...