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

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



前言

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


一、配置回调服务

1.配置回调服务入口:

回调配置入口

2.配置前:

配置页面
上图中第一个空填后端服务中要接受企业微信消息的接口路径。(第二节重点讲解)
Token和EncodingAESKey随机获取即可,不过获取后要和后端的解析代码对应。
注意红框中的消息类型,如果不勾选这一类的消息不会做回调。

3.配置后

这里的回调服务器不一定要域名,用ip加端口也一样能回调成功,配置成功页面请看下图:
配置成功页面
建议获取Token和EncodingAESKey后就立刻配置到后端的配置文件中。
当服务部署到服务器后在复制配置文件中的内容到该页面即可。
想要成功配置需要完成本章第三节,并且把服务部署到服务器上才行!!!!!!!!!!

二、解密工具

企业微信的回调需要AES加解密
可以看企业微信的官方接口加解密方案说明,当然不用看懂,会用就行了。
本章主要用java语言做后端服务的开发,因此主要看java的AES加解密,这是企业微信提供的Java版加解密工具 JavaAES加解密工具包
正式在项目中使用可以按我这个目录存放
在这里插入图片描述

加解密工具使用实现

主要是看WXBizMsgCrypt的VerifyURL或者DecryptMsg方法。
首先我们需要new一个WXBizMsgCrypt的实例,必须有三个入参:

参数描述
token配置消息服务器时随机生成的Token
encodingAesKey配置消息服务器时随机生成的EncodingAESKey
receiveid在内部应用开发中这里填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)的,并且解密工具包的入参顺序没问题,就能成功。还有一个麻烦的点在于没办法本地测试只能部署到服务器后调用才能判断接口是否正确。

Flask是一个轻量级的Python Web框架,它可以用来构建Web应用程序。企业微信应用是一种能够在企业微信平台上运行的应用程序,可以帮助企业内部进行沟通、协作和管理。 在Flask中,我们可以使用Flask的路由机制来处理企业微信应用回调请求。回调是指企业微信平台在某些事件发生时向企业微信应用发送HTTP请求,应用需要对这些请求进行响应。 首先,我们需要配置企业微信应用回调URL,即将该URL与Flask应用中的某个路由函数进行绑定。当企业微信平台有回调请求时,Flask应用会自动调用与该URL绑定的路由函数。 在路由函数中,我们可以根据请求的类型和内容进行处理。例如,可以根据请求的事件类型来执行相应的操作,如发送消息、获取通讯录信息等。同时,还可以根据请求的参数来获取相应的数据,并进行相应的处理和返回。 在处理回调请求时,还需要注意验证请求的有效性。企业微信平台会通过加密算法将请求进行加密,我们需要按照约定的方式进行解密,并校验相关参数的合法性,以确保请求的安全性和有效性。 总的来说,Flask提供了便捷的路由功能,可以轻松地处理企业微信应用回调请求。通过合理地运用Flask的路由机制,我们可以根据不同的事件和请求类型,进行相应的操作和处理,实现丰富多样的企业微信应用功能。同时,确保回调请求的有效性和安全性也是非常重要的。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值