缠丝猫 发表于 2024-9-10 13:41:03

企业微信-内部应用回调服务的应用与实现

-# 企业微信-内部应用回调服务的应用与实现
第一章 域名与ip白名单
第二章 api的调用与实现
第三章 回调服务的应用与实现


前言

哈喽!之前我们聊了api的手动调用这章我们来聊聊回调服务。
起首什么是企业微信的回调服务?还是拿企业成员来聊吧(这个相对简朴)。
比如有成员离职然后咱们内部系统中有资源属于他,是一定要做资源转交或者迁移的。
做迁移时系统需要知道迁移谁的数据,这里逻辑层面上有两种方式:
1、定时任务-每秒访问一次通讯录有成员变动就执行迁移。
2、回调模式-开一个接口让企业微信调用来告诉你成员变得信息。企微回调服务入口
由于企业微信有回调模式因此本人极力不保举定时任务方案,但回调服务也有丢失消息的弊端。
下一章我将介绍怎样利用利用RabiitMQ使其回调消息不丢失,有爱好的朋友可以看一下。
(个人学习利用并不全面,如有错误欢迎指正。绝对听劝!)
一、配置回调服务

1.配置回调服务入口:

https://i-blog.csdnimg.cn/direct/975439997af84a2a9cf08cf57fda09ee.png
2.配置前:

https://i-blog.csdnimg.cn/direct/976360011bd348a1b145ec465f4a6c97.png
上图中第一个空填后端服务中要担当企业微信消息的接口路径。(第二节重点讲解)
Token和EncodingAESKey随机获取即可,不过获取后要和后端的解析代码对应。
注意红框中的消息类型,如果不勾选这一类的消息不会做回调。
3.配置后

这里的回调服务器不一定要域名,用ip加端口也一样能回调乐成,配置乐成页面请看下图:
https://i-blog.csdnimg.cn/direct/f1d9af7467894c4bbc601f91ea8b9173.png
建议获取Token和EncodingAESKey后就立即配置到后端的配置文件中。
当服务部署到服务器后在复制配置文件中的内容到该页面即可。
想要乐成配置需要完成本章第三节,并且把服务部署到服务器上才行!!!!!!!!!!
二、解密工具

企业微信的回调需要AES加解密
可以看企业微信的官方接口加解密方案阐明,固然不用看懂,会用就行了。
本章主要用java语言做后端服务的开发,因此主要看java的AES加解密,这是企业微信提供的Java版加解密工具 JavaAES加解密工具包
正式在项目中利用可以按我这个目录存放
https://i-blog.csdnimg.cn/direct/6e8aeaf52ea9430fb2b37748f895199f.png
加解密工具利用实现

主要是看WXBizMsgCrypt的VerifyURL或者DecryptMsg方法。
起首我们需要new一个WXBizMsgCrypt的实例,必须有三个入参:
参数形貌token配置消息服务器时随机生成的TokenencodingAesKey配置消息服务器时随机生成的EncodingAESKeyreceiveid在内部应用开发中这里填corpId就可以了         WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(callBackToken, callBackEncodingAESKey, corpId);
当我们有wxcpt 这个实例后可以调用VerifyURL方法或者DecryptMsg来解密
这个两个方法的公共参数如下:
参数形貌msgSignature加密签名由企业微信回调时提供timestamp时间戳同上由企业微信回调时提供nonce随机数戳同上由企业微信回调时提供 VerifyURL方法在上面三个参数的环境下还需要传入echoStr参数,代码如下:
        //echoStr加密密文,只有在配置回调服务时企业微信会发一段密文让你解析,这个密文就是放到这个参数里的。
        //一般解密成功后就直接将结果return就行了。
        wxcpt.VerifyURL(msgSignature, timestamp, nonce, echoStr);
DecryptMsg方法将echoStr参数替换为xml解密后得到明文xml,代码如下:
        //xml也是企业微信回调时穿过来的密文xml
        String plainXml = wxcpt.DecryptMsg(msgSignature, timestamp, nonce, xml);
解密工具可以不用研究的很透彻,会用就行。深究伤脑!!!
三、回调接口编写

1.环境版本

   JDK:17.0.12
mavem:3.6.3
spring-boot:3.3.3
2.引入库

利用lombok来简化实体类的代码
jaxb-api和jaxb-core以及jaxb-runtime用于解析企微回调的名为xml数据
      <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
      </dependency>
      <!--xml解析工具-->
      <dependency>
            <groupId>javax.xml.bind</groupId>
            <artifactId>jaxb-api</artifactId>
            <version>2.3.1</version>
      </dependency>
      <dependency>
            <groupId>com.sun.xml.bind</groupId>
            <artifactId>jaxb-core</artifactId>
            <version>2.3.0.1</version>
      </dependency>
      <!-- 添加 JAXB 运行时实现 -->
      <dependency>
            <groupId>org.glassfish.jaxb</groupId>
            <artifactId>jaxb-runtime</artifactId>
            <version>2.3.1</version>
      </dependency>
3.配置文件

qywx:
url: https://qyapi.weixin.qq.com #企业微信api出口根路径
#如果嫌public-path麻烦可以舍弃这个配置url用:https://qyapi.weixin.qq.com/cgi-bin代替
public-path: cgi-bin #接口目录,最终会拼接在url后面,
debug-mode: false #是否开启api的debug-mode模式
corpId: 你的企业ID
secret: 你的应用密钥
call-back:
    #最好用自己在企业微信上随机生成的
    token: 自己生成
    encodingAESKey: 自己生成
token和encodingAESKey看第一节的第二点随机获取就行了!
4.控制层

参数名称形貌msgSignature企业微信加密签名就是形貌的那样该参数由企业微信回调时提供timestamp时间戳同上nonce随机数同上echoStr加密字符该字符串是由在配置回调服务器时有效,由企微传递xml加密文档全部企微的回调都会有该参数,通过解析它才气获取回调事件内容 该接口必须包罗这五个参数并且是开放的(有安全框架的需忽略权限,其它自界说拦截逻辑请过滤该接口)
@RestController
public class CallBackController {

    private final CallbackService callbackService;
    public CallBackController(CallbackService callbackService) {
      this.callbackService = callbackService;
    }

    /**
   * 回调接口,由企业微信调用请开放
   * 注意:
   * echoStr,get
   * xml
   * @param msgSignature企业微信加密签名
   * @param timestamp   时间戳
   * @param nonce         随机数
   * @param echoStr       加密字符
   * @param xml         加密文档
   */
    @RequestMapping("/callback")
    public String callback(@RequestParam(value = "msg_signature", required = false) String msgSignature,
                              @RequestParam(value = "timestamp", required = false) String timestamp,
                              @RequestParam(value = "nonce", required = false) String nonce,
                              @RequestParam(value = "echostr", required = false) String echoStr,
                              @RequestBody(required = false) String xml)
    {
      return callbackService.callback(msgSignature,timestamp,nonce,echoStr,xml);
    }

}
5、服务层

public class CallbackService {

    @Value("${qywx.corpId}")
    private String corpId;

    @Value("${qywx.call-back.token}")
    private String callBackToken;
    @Value("${qywx.call-back.encodingAESKey}")
    private String callBackEncodingAESKey;

    public String callback(String msgSignature, String timestamp, String nonce, String echoStr,String xml) {
      if (echoStr==null&&xml==null){
            return "解析内容为空,解析失败";
      }
      if (msgSignature==null||timestamp==null||nonce==null){
            return "辅助解析参数为空,解析失败";
      }

      String result = "成功";
      try {
            WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(callBackToken, callBackEncodingAESKey, corpId);
            //这里注意在配置url时企业微信会调用一次该接口,此时echoStr是有值的
            //为了通过企业微信的校验这里需要解密并且将明文返回
            if (echoStr!=null&&!echoStr.isBlank()){
                //调用工具包解密
                return wxcpt.VerifyURL(msgSignature, timestamp, nonce, echoStr);
            }else {
                //如果echoStr没值,那肯定是企业的业务回调了
                String plainXml = wxcpt.DecryptMsg(msgSignature, timestamp, nonce, xml);

                //企业微信回调的明文是xml,下面我用javax.xml来做一个解析。
                CommonEventData xmlObject = XMLUtil.convertXmlStrToObject(CommonEventData.class, plainXml);
                //因为企业微信有各种各样的回调xml类型,因此需要做抽象类,并以对应子类返回数据
                if ("text".equals(xmlObject.getMsgType())){
                  System.out.println("text");
                  //文本消息回调的业务逻辑
                  TextMsgEventData textMsgEventData = XMLUtil.convertXmlStrToObject(TextMsgEventData.class, xml);
                  System.out.println(textMsgEventData);
                }
                //如果你需要加其它业务逻辑需要自己建BaseEventData的子类来对应
                //当然这只是我使用了javax.xml来解析xml的案例,有更好用的xml包可以替换
                if ("event".equals(xmlObject.getMsgType())){
                  //事件消息回调的业务逻辑,审批和成员变动都是该类型
                  //该类型的消息还有很多不同内容的xml需要特别注意(用我这个方法就需要建很多的子类来对应)
                  System.out.println("event");
                  //这里我们忽略Event的类型直接用ChangeType来判断使用哪个类进行封装
                  switch(xmlObject.getChangeType()){
                        case "create_user":
                        case "update_user":
                        case "delete_user":
                            UserEventData userEventData = XMLUtil.convertXmlStrToObject(UserEventData.class, xml);
                            System.out.println(userEventData);
                  }
                }
            }
      } catch (AesException e) {
            throw new RuntimeException(e);
      }
      return result;
    }
}
六、项目源码

项目gitee地址
总结

本章主要难点是编写正确的回调接口,只要注意配置文件的内容和企业微信上的逐一对应(Token和EncodingAESKey)的,并且解密工具包的入参次序没问题,就能乐成。还有一个贫苦的点在于没办法当地测试只能部署到服务器后调用才气判断接口是否正确。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: 企业微信-内部应用回调服务的应用与实现