之前一直没有写这篇文章,是觉得企微的服务商应用相对简单。第二个原因是最近在弄钉钉的ISV上架,所以时间不是很充足。正题开始……
1、使用管理员登录服务商管理后台
企业微信-服务商后台-登录地址https://open.work.weixin.qq.com/wwopen/login2、输入基本信息及认证
1、登录后,直接创建创建网页应用,如下图。
2、应用详情-使用配置-参照下面的教程。主页地址是固定的,只需要写入自己的appid和redirect_uri的地址就行。这里需要注意,可信域名必须配置一下,需要注意的是这个一级域名一旦使用的服务商应用,那么自建应用是无法在使用这个域名的,即便是不同的二级域名也不可以。这个还是比较坑,导致我们重新申请了一个一级域名来服务自建应用。
3、可信域名配置,使用配置-点击【编辑】,然后点击【校验可信域名归属】,然后下载这个文件到nginx配置的域名文件夹下,只要通过步骤2的地址可以访问到就算验证通过。nginx的配置参照下面的这个文章。
nginx配置websocket或https的转发教程_renkai721的博客-CSDN博客_nginx websocket转发nginx配置http,https,ssl,websocket转发https://blog.csdn.net/renkai721/article/details/125991270
4、数据回调的配置
1、pom.xml中添加解析XML格式内容
org.jdom
jdom2
2.0.6
commons-codec
commons-codec
1.15
2、properties文件,不需要那么多,命名更具自己的喜好,这一看就是参照了gitee的binarywang/weixin-java-cp-demo,这个demo如果初学者可以看看,然后自己封装。
3、核心解密controller.java
package cn.renkai721.controller;
import cn.renkai721.bean.*;
import cn.renkai721.configuration.QywxProperties;
import cn.renkai721.service.*;
import cn.renkai721.util.HttpUtil;
import cn.renkai721.util.MsgUtil;
import cn.renkai721.util.WxUtil;
import cn.renkai721.wechataes.WXBizMsgCrypt;
import com.alibaba.druid.util.StringUtils;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Map;
@EnableAsync
@RestController
@RequestMapping("/d3f")
@Slf4j
public class D3f2Controller {
@Resource
private RedissonClient redissonClient;
@Autowired
private RestTemplate restTemplate;
@Autowired
private D3fService d3fService;
@GetMapping(produces = "text/plain;charset=utf-8")
public void d3fGet(@RequestParam(name = "msg_signature", required = false) String signature,
@RequestParam(name = "timestamp", required = false) String timestamp,
@RequestParam(name = "nonce", required = false) String nonce,
@RequestParam(name = "echostr", required = false) String echostr,
HttpServletResponse response) throws Exception {
response.setContentType("text/html;charset=utf-8");
response.setStatus(HttpServletResponse.SC_OK);
WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(
MsgUtil.val("wechat.cp.appConfigs[0].token"),
MsgUtil.val("wechat.cp.appConfigs[0].aesKey"),
MsgUtil.val("wechat.cp.corpId"));
// 需要返回的明文
String sEchoStr = "";
try {
sEchoStr = wxcpt.VerifyURL(signature, timestamp, nonce, echostr);
log.info("resp sEchoStr={}",sEchoStr);
response.getWriter().print(sEchoStr);
return;
} catch (Exception e) {
// 验证URL失败,错误原因请查看异常
e.printStackTrace();
}
response.getWriter().print("非法请求");
return;
}
@PostMapping(produces = "application/xml; charset=UTF-8")
public void d3fPost(@RequestParam("msg_signature") String signature,
@RequestParam("timestamp") String timestamp,
@RequestParam("nonce") String nonce,
HttpServletResponse response,
HttpServletRequest request) throws Exception {
String success = "success";
String type = request.getParameter("type");
String corpid = request.getParameter("corpid");
log.info("接收d3f post请求:[signature=[{}], timestamp=[{}], nonce=[{}], type=[{}], corpid=[{}] ]",
signature, timestamp, nonce, type, corpid);
try{
response.setContentType("text/html;charset=utf-8");
response.setStatus(HttpServletResponse.SC_OK);
String id = "";
// 访问应用和企业回调传不同的ID
if("data".equals(type)){
// 企微后台设置【数据回调URL】的链接为https://wx.naturobot.com/qywx/d3f?type=data&corpid=$CORPID$
id = corpid;
} else {
id = MsgUtil.val("suite_id");
}
WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(MsgUtil.val(
"wechat.cp.appConfigs[0].token"),
MsgUtil.val("wechat.cp.appConfigs[0].aesKey"),
id);
// 密文,对应POST请求的数据
String postData = "";
// 获取加密的请求消息:使用输入流获得加密请求消息postData
ServletInputStream in = request.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
// 作为输出字符串的临时串,用于判断是否读取完毕
String tempStr = "";
while(null != (tempStr=reader.readLine())){
postData += tempStr;
}
String suiteXml = wxcpt.DecryptMsg(signature, timestamp, nonce, postData);
Map suiteMap = WxUtil.transferXmlToMap(suiteXml);
log.info("\n req map={}", suiteMap);
if("suite_ticket".equals(suiteMap.get("InfoType"))){
// https://developer.work.weixin.qq.com/document/10975#%E8%8E%B7%E5%8F%96%E7%AC%AC%E4%B8%89%E6%96%B9%E5%BA%94%E7%94%A8%E5%87%AD%E8%AF%81
// 主动推送SuiteTicket直接写入
// 每十分钟更新一次