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

This commit is contained in:
YunaiV 2023-01-01 23:48:10 +08:00
parent 275a1b10f6
commit c671b01b0a
6 changed files with 105 additions and 16 deletions

View File

@ -0,0 +1,40 @@
package cn.iocoder.yudao.module.mp.controller.admin.open;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.module.mp.controller.admin.open.vo.MpOpenCheckSignatureReqVO;
import cn.iocoder.yudao.module.mp.framework.mp.core.MpServiceFactory;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.mp.api.WxMpService;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
@Api(tags = "管理后台 - 公众号回调")
@RestController
@RequestMapping("/mp/open")
@Validated
@Slf4j
public class MpOpenController {
@Resource
private MpServiceFactory mpServiceFactory;
@ApiOperation("校验签名") // 参见 https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Access_Overview.html 文档
@GetMapping(value = "/{appId}", produces = "text/plain;charset=utf-8")
public String checkSignature(@PathVariable("appId") String appId,
MpOpenCheckSignatureReqVO reqVO) {
log.info("[checkSignature][appId({}) 接收到来自微信服务器的认证消息({})]", appId, reqVO);
// 校验请求签名
WxMpService wxMpService = mpServiceFactory.getRequiredMpService(appId);
// 校验通过
if (wxMpService.checkSignature(reqVO.getTimestamp(), reqVO.getNonce(), reqVO.getSignature())) {
return reqVO.getEchostr();
}
// 校验不通过
return "非法请求";
}
}

View File

@ -0,0 +1,34 @@
package cn.iocoder.yudao.module.mp.controller.admin.open.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.springframework.web.bind.annotation.RequestParam;
import javax.validation.constraints.NotEmpty;
@ApiModel("管理后台 - 公众号校验签名 Request VO")
@Data
public class MpOpenCheckSignatureReqVO {
@ApiModelProperty(value = "微信加密签名", required = true, example = "490eb57f448b87bd5f20ccef58aa4de46aa1908e")
@NotEmpty(message = "微信加密签名不能为空")
private String signature;
@ApiModelProperty(value = "时间戳", required = true, example = "1672587863")
@NotEmpty(message = "时间戳不能为空")
private String timestamp;
@ApiModelProperty(value = "随机数", required = true, example = "1827365808")
@NotEmpty(message = "随机数不能为空")
private String nonce;
@ApiModelProperty(value = "随机字符串", required = true, example = "2721154047828672511")
@NotEmpty(message = "随机字符串不能为空")
@SuppressWarnings("SpellCheckingInspection")
private String echostr;
}

View File

@ -0,0 +1,6 @@
/**
* 提供 RESTful API 给前端
* 1. admin 提供给管理后台 yudao-ui-admin 前端项目
* 2. app 提供给用户 APP yudao-ui-app 前端项目它的 Controller VO 都要添加 App 前缀用于和管理后台进行区分
*/
package cn.iocoder.yudao.module.mp.controller;

View File

@ -94,65 +94,65 @@ public class DefaultMpServiceFactory implements MpServiceFactory {
// 第二步创建 WxMpService 对象 // 第二步创建 WxMpService 对象
WxMpService service = new WxMpServiceImpl(); WxMpService service = new WxMpServiceImpl();
service.setWxMpConfigStorage(configStorage); service.setWxMpConfigStorage(configStorage);
return null; return service;
} }
private WxMpMessageRouter buildMpMessageRouter(WxMpService mpService) { private WxMpMessageRouter buildMpMessageRouter(WxMpService mpService) {
final WxMpMessageRouter newRouter = new WxMpMessageRouter(mpService); WxMpMessageRouter router = new WxMpMessageRouter(mpService);
// 记录所有事件的日志异步执行 // 记录所有事件的日志异步执行
newRouter.rule().handler(logHandler).next(); router.rule().handler(logHandler).next();
// 接收客服会话管理事件 // 接收客服会话管理事件
newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT) router.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
.event(WxMpEventConstants.CustomerService.KF_CREATE_SESSION) .event(WxMpEventConstants.CustomerService.KF_CREATE_SESSION)
.handler(kfSessionHandler).end(); .handler(kfSessionHandler).end();
newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT) router.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
.event(WxMpEventConstants.CustomerService.KF_CLOSE_SESSION) .event(WxMpEventConstants.CustomerService.KF_CLOSE_SESSION)
.handler(kfSessionHandler) .handler(kfSessionHandler)
.end(); .end();
newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT) router.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
.event(WxMpEventConstants.CustomerService.KF_SWITCH_SESSION) .event(WxMpEventConstants.CustomerService.KF_SWITCH_SESSION)
.handler(kfSessionHandler).end(); .handler(kfSessionHandler).end();
// 门店审核事件 // 门店审核事件
newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT) router.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
.event(WxMpEventConstants.POI_CHECK_NOTIFY) .event(WxMpEventConstants.POI_CHECK_NOTIFY)
.handler(storeCheckNotifyHandler).end(); .handler(storeCheckNotifyHandler).end();
// 自定义菜单事件 // 自定义菜单事件
newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT) router.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
.event(WxConsts.MenuButtonType.CLICK).handler(menuHandler).end(); .event(WxConsts.MenuButtonType.CLICK).handler(menuHandler).end();
// 点击菜单连接事件 // 点击菜单连接事件
newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT) router.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
.event(WxConsts.MenuButtonType.VIEW).handler(nullHandler).end(); .event(WxConsts.MenuButtonType.VIEW).handler(nullHandler).end();
// 关注事件 // 关注事件
newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT) router.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
.event(WxConsts.EventType.SUBSCRIBE).handler(subscribeHandler) .event(WxConsts.EventType.SUBSCRIBE).handler(subscribeHandler)
.end(); .end();
// 取消关注事件 // 取消关注事件
newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT) router.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
.event(WxConsts.EventType.UNSUBSCRIBE) .event(WxConsts.EventType.UNSUBSCRIBE)
.handler(unsubscribeHandler).end(); .handler(unsubscribeHandler).end();
// 上报地理位置事件 // 上报地理位置事件
newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT) router.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
.event(WxConsts.EventType.LOCATION).handler(locationHandler) .event(WxConsts.EventType.LOCATION).handler(locationHandler)
.end(); .end();
// 接收地理位置消息 // 接收地理位置消息
newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.LOCATION) router.rule().async(false).msgType(WxConsts.XmlMsgType.LOCATION)
.handler(locationHandler).end(); .handler(locationHandler).end();
// 扫码事件 // 扫码事件
newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT) router.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
.event(WxConsts.EventType.SCAN).handler(scanHandler).end(); .event(WxConsts.EventType.SCAN).handler(scanHandler).end();
// 默认 // 默认
newRouter.rule().async(false).handler(msgHandler).end(); router.rule().async(false).handler(msgHandler).end();
return newRouter; return router;
} }
} }

View File

@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.mp.framework.mp.core; package cn.iocoder.yudao.module.mp.framework.mp.core;
import cn.hutool.core.lang.Assert;
import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO; import cn.iocoder.yudao.module.mp.dal.dataobject.account.MpAccountDO;
import me.chanjar.weixin.mp.api.WxMpMessageRouter; import me.chanjar.weixin.mp.api.WxMpMessageRouter;
import me.chanjar.weixin.mp.api.WxMpService; import me.chanjar.weixin.mp.api.WxMpService;
@ -28,6 +29,12 @@ public interface MpServiceFactory {
*/ */
WxMpService getMpService(String appId); WxMpService getMpService(String appId);
default WxMpService getRequiredMpService(String appId) {
WxMpService wxMpService = getMpService(appId);
Assert.notNull(wxMpService, "找到对应 appId({}) 的 WxMpService请核实", appId);
return wxMpService;
}
/** /**
* 获得 appId 对应的 WxMpMessageRouter 实例 * 获得 appId 对应的 WxMpMessageRouter 实例
* *

View File

@ -92,6 +92,7 @@ yudao:
security: security:
permit-all_urls: permit-all_urls:
- /admin-ui/** # /resources/admin-ui 目录下的静态资源 - /admin-ui/** # /resources/admin-ui 目录下的静态资源
- /admin-api/mp/open/** # 微信公众号开放平台,微信回调接口,不需要登录
swagger: swagger:
title: 管理后台 title: 管理后台
description: 提供管理员管理的所有功能 description: 提供管理员管理的所有功能
@ -119,6 +120,7 @@ yudao:
- /admin-api/system/sms/callback/* # 短信回调接口,无法带上租户编号 - /admin-api/system/sms/callback/* # 短信回调接口,无法带上租户编号
- /admin-api/pay/notify/callback/* # 支付回调通知,不携带租户编号 - /admin-api/pay/notify/callback/* # 支付回调通知,不携带租户编号
- /jmreport/* # 积木报表,无法携带租户编号 - /jmreport/* # 积木报表,无法携带租户编号
- /admin-api/mp/open/** # 微信公众号开放平台,微信回调接口,无法携带租户编号
ignore-tables: ignore-tables:
- system_tenant - system_tenant
- system_tenant_package - system_tenant_package