企业微信的外部联系人回调处理技巧

2023-11-05

一、关于设置接收事件服务器的信息

       在企业微信管理后台的“客户联系-客户”页面,点开“API”小按钮,再点击“接收事件服务器”配置,进入配置页面,要求填写URL、Token、EncodingAESKey三个参数。

  • URL是企业后台接收企业微信推送请求的访问协议和地址,支持http或https协议(建议使用https)。
  • Token可由企业任意填写,用于生成签名。
  • EncodingAESKey用于消息体的加密,是AES密钥的Base64编码。

如下图所示:

 从以上图,我们可以知道这里配置的信息,是配置我们本地的路径,远程企业微信外部联系人变更,会推送到我们本地,进而处理我们需要的数据。

问题:A、url配置的路径是怎么样的?

           B、推送到本地数据的路径是否也是URL配置路径?

二、解决思路

     针对A、B问题,远程URL配置首先需要验证URL的有效性,其次再是消息的推送。详情说明请看:关于接收消息

    本地实现策略:定义一个路径,既符合GET请求又符合POST请求,可以定义两个方法,相同的请求路径,分GET请求和POST请求。对于加密解密,这里不在赘述。

如下所示:

/**
     * 外部联系人业务处理
     * @param cropId
     * @return
     */
    @PostMapping(value = "/callback/external-user/{cropId}")
    public String callbackExternalUserMsg(HttpServletRequest request, HttpServletResponse response, @PathVariable String cropId,@RequestBody String postData){
        log.info("企业微信CorpId:{},企业微信外部联系人事件消息通知:\n {} ",cropId,postData);
        String encodingAesKey = qyEncodingAesKey;
        String token = qyToken;

        try {
            JAXBContext context = JAXBContext.newInstance(QyCustVo.class);
            Unmarshaller unmarshaller = context.createUnmarshaller();
            QyCustVo msgVo = (QyCustVo) unmarshaller.unmarshal(new StringReader(postData));
            msgVo.setXmlStr(postData);

            if (StringUtil.isNotEmpty(msgVo.getEncrypt())) {
                String nonce = request.getParameter("nonce");
                String timestamp = request.getParameter("timestamp");
                String msgSignature = request.getParameter("msg_signature");
                log.info("企业微信加密签名:{},时间戳:{},随机数:{}" , msgSignature,timestamp,nonce);

                WxAESInfo wxcpt = new WxAESInfo(cropId, encodingAesKey, token);
                String result = WxAESUtil.decryptMsg(wxcpt, msgVo.getEncrypt(), msgSignature, timestamp, nonce);
                msgVo = (QyCustVo) unmarshaller.unmarshal(new StringReader(result));
                msgVo.setXmlStr(result);
                log.info("接收事件消息解密后的消息体:{}",result);
            }
            if (StringUtil.isNotBlank(msgVo.getXmlStr())){
                String topic = "qywxopen-externalUserMsg";
                boolean sendMessage = mqService.sendMessage(topic, msgVo.getXmlStr(), false);
                log.info("外部联系人变更回调的kafka主题:{},发送的状态:{}",topic,sendMessage);
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return "success";
    }



/**
     * 外部联系人URL路径校验
     * @param request
     * @param response
     * @param cropId
     * @throws IOException
     */
    @RequestMapping(value = "/callback/external-user/{cropId}", method = RequestMethod.GET)
    public void callbackExternalUser(HttpServletRequest request, HttpServletResponse response, @PathVariable String cropId) throws IOException {
        log.info("企业微信CorpId:{}",cropId);
        String encodingAesKey =qyEncodingAesKey.trim();
        String token = qyToken.trim();

        String nonce = request.getParameter("nonce").trim();
        String timestamp = request.getParameter("timestamp").trim();
        String msgSignature = request.getParameter("msg_signature").trim();
        String echostr = request.getParameter("echostr").trim();
        echostr = echostr.replace(" ", "+");
        log.info("企业微信加密签名:{},时间戳:{},随机数:{},加密的字符串:{}" , msgSignature,timestamp,nonce,echostr);
        String result = null;
        PrintWriter printWriter = response.getWriter();
        try {
            WXBizMsgCrypt wxBizMsgCrypt = new WXBizMsgCrypt(token,encodingAesKey,cropId);
            result = wxBizMsgCrypt.verifyUrl(msgSignature,timestamp,nonce,echostr);
            log.info("验证URL解密后的消息体:\n{}",result);
        }catch (Exception e){
            e.printStackTrace();
        }
        if (StringUtil.isEmpty(result)){
            result = "success";
        }
        printWriter.print(result);
        printWriter.close();
    }

三、资料链接

接收信息:https://work.weixin.qq.com/api/doc/90000/90135/90238#%E9%AA%8C%E8%AF%81URL%E6%9C%89%E6%95%88%E6%80%A7

加解密:https://work.weixin.qq.com/api/doc/90000/90139/90968

代码地址:https://github.com/krycai/gc-framework/tree/master/gc-wx

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

企业微信的外部联系人回调处理技巧 的相关文章

  • 生活中那些六 “有” 的人

    1 有承诺 一些事情开始的时候总会有些协议与约定 我们称其为承诺 我们必须遵守承诺 即使是约会也要遵守 也不能迟到 迟到这件事不但会妨碍我们所有人 还意味着迟到者不尊重大家的时间 这种约定从某种意义上来讲也是承诺 如果你来晚了 这就表示你的
  • 蓝桥杯考生规则

    2017年模拟赛 本科组 考生须知 l 考试开始后 选手首先下载题目 并使用考场现场公布的解压密码解压试题 l 考试时间为4小时 时间截止后 提交答案无效 l 在考试强制结束前 选手可以主动结束考试 需要身份验证 结束考试后将无法继续提交或
  • java计算机毕业设计火车订票系统源码+mysql数据库+系统+lw文档+部署

    java计算机毕业设计火车订票系统源码 mysql数据库 系统 lw文档 部署 java计算机毕业设计火车订票系统源码 mysql数据库 系统 lw文档 部署 本源码技术栈 项目架构 B S架构 开发语言 Java语言 开发软件 idea
  • Tomcat调优

    问题定位 对于Tomcat的处理耗时较长的问题主要有当时的并发量 session数 内存及内存的回收等几个方面造成的 出现问题之后就要进行分析了 1 关于Tomcat的session数目 这个可以直接从Tomcat的web管理界面去查看即可
  • Go语言学习13-类型转换

    类型转换 引言 类型转换 1 概念 2 数值类型之间的转换 3 与string类型相关的转换 4 别名类型值之间的转换 结语 引言 在上一篇博文中 我们介绍了 Go 语言的 数据的使用 本篇博文 我们将介绍 Go 语言的类型转换 类型转换
  • HTTP头的Expires与Cache-control

    1 概念 Cache control用于控制HTTP缓存 在HTTP 1 0中可能部分没实现 仅仅实现了Pragma no cache 数据包中的格式 Cache Control cache directive cache directiv
  • 程序员的十个等级

    转载自 http blog csdn net fx0000001 article details 50397265 如果你还迷茫请看这里 如果你很牛逼请看这里 如果你很自傲请看这里 总有你想学会的 自西方文艺复兴以来 中国在自然科学方面落后
  • 不带头结点的单链表

    建立结构体 和带头结点但单链表一样 按需建立即可 我以建立一个储存学生信息的链表举例 typedef struct node char name 20 int number struct node next Node LinkList 单链
  • 探索全桥电机驱动模块:实现精确控制与高效驱动

    全桥电机驱动模块是一种在现代工程应用中广泛使用的电机驱动方式 对于需要精确控制和高效驱动的场景 如机器人 无人机 电动车等 全桥电机驱动模块提供了理想的解决方案 本文将介绍全桥电机驱动模块的原理和实际应用场景 并对几种常见的全桥驱动芯片进行
  • csdn的Markdown行首缩进的两种方法,非常全

    csdn的行首缩进 鉴于不同编辑器的Markdown语法略微不同 故缩进也略不同 1 特殊占位符 不缩进 行首缩进 nbsp 行首缩进 160 四分之一中文占位符 行首缩进 8197 四分之一中文占位符 行首缩进 ensp 行首缩进 819
  • Spring中Bean的生命周期

    Spring Bean的生命周期是从Bean 实例化之后 即通过反射创建出对象之后 到Bean成为一个完整对象 最终存储到单例池中 这个过程被称为Spring Bean的生命周期 Spring Bean的生命周期大体上分为四个阶段 实例化
  • vue2.0项目调用多个IP接口

    项目中经常遇到跨域问题 最简单的方式就在本地配置代理 可偶尔遇到一个页面里面需要调用来自两个以上不同IP段的接口 多个IP要怎么配置代理呢 请往下看 在项目目录 config index js文件配置代理 module exports de
  • pytest

    一 pytest是单元测试框架 单元测试 对软件开发中 对软件的最小单位 函数 方法 进行正确性检查测试 java框架 jnuit和testing python框架 unittest和pytest 流程 i 测试发现 从多个文件中找到测试用
  • 英俊飘逸气宇轩昂——同人立绘征集大赛凤九天·金奖

    导语 本期介绍的作品是由来自江西科技师范大学的计世平设计的凤九天形象 荣获了本次大赛凤九天组别的金奖 2020年12月22日 由首都版权协会联合全国部分高等院校和链游玩家及部分企业共同举办的 2020同人立绘征集大赛 正式启动 并于2021
  • 详解pop()和push()方法

    pop 是移除堆栈顶部的元素并且返回它的值 push 是把对象压入堆栈的顶部 这里的堆栈不是特指栈 是LinkedList中特有的方法 LinkedHashset和LinkedHashMap ArrayList中没有此方法 下面是个小李子
  • Unity UV 水效果实现

    Unity UV 水效果实现 Unity Water Shader 组件搭载 基本参数调节 所需图片 效果呈现 Unity Water Shader Shader Custom SeaWave Properties WaterTex 水纹理
  • 潘周聃之Python分聃 -----数字雨加入潘周聃运动曲线

    作者 勇敢di牛牛 个人项目地址 englishlearningapp 个人简介 有一年工作经验的大学生 工作 汽车系统应用开发 阿里集团 个人网站 牛牛 小窝 独学而无友 则孤陋而寡闻 前言 相信各位同学最近一定被潘周聃刷屏和洗脑了 互联
  • seaborn可视化——一文搞懂heatmap参数

    文章目录 data cmap linewidths linecolor square ax annot 指定为True 指定为同形状数组 vmax vmin annot kws mask xticklabels yticklabels 设置
  • linux 命令 ls 与 ls -lrt 的区别

    ls lrt 表示按修改时间倒序列出当前工作目录下的文件 ls l 表示按名称顺序正序列出当前工作目录下的文件 1 ls 表示列出当前目录下的文件 后面的 lrt 是这个命令的一些选项补充 lrt 实际上是代表了 l r t 这三个选项集合

随机推荐

  • 对sklearn中transform()和fit_transform()的深入理解

    在用机器学习解决问题时 往往要先对数据进行预处理 其中 z score归一化和Min Max归一化是最常用的两种预处理方式 可以通过sklearn preprocessing模块导入StandardScaler 和 MinMaxScaler
  • k8s--基础--21--Statefulset

    k8s 基础 21 Statefulset 1 概念 StatefulSet是为了解决有状态服务的问题而设计 对应Deployments和ReplicaSets是为无状态服务 1 1 应用场景 稳定的持久化存储 即Pod重新调度后还是能访问
  • linux增大交换空间,Linux系统增加交换空间的方法

    Linux系统增加交换空间有两种方法 严格的说 在系统安装完后只有一种方法可以增加swap 那就是本文的第二种方法 至于第一种方法应该是安装系统时设置交换区 1 使用分区 在安装OS时划分出专门的交换分区 空间大小要事先规划好 启动系统时自
  • 【事业单位笔试】zrzyb信息中心-社会招聘-笔试记录

    写在前面的话 虽然说本人在21年校招时有北京银行 农银金科 中信银行研发 京东发 邮储银行 中软 郑州铁路局等的offer 奈何个人原因还是选择了有北京户口的现在的工作单位 虽然只有两年 但也是时候准备考虑一下今后的发展了 感谢大家支持 我
  • 电机控制进阶——PID速度控制

    之前的几篇文章 电机控制基础篇 介绍的电机编码器原理 定时器输出PWM 定时器编码器模式测速等 本篇在前几篇的基础上 继续来学习电机控制 通过PID算法 来进行电机的速度控制 并进行实验测试 PID基础 PID即 Proportional
  • 海外新冠疫情 API数据接口

    海外新冠疫情 计费模式 免费额度 点数单价 每日限制 会员免费 100次 免费 10000次 更新时间 2022 07 11 02 51 15接口状态 正常 返回海外新冠数据 请求地址 HTTPGET POST https www mait
  • 毕业设计 嵌入式 单片机智能路灯

    文章目录 1 简介 2 绪论 2 1 项目背景 2 2 需求分析 3 系统设计 3 1 功能设计 3 1 1 系统角色分析 3 1 2 开发环境 3 2 总体设计 3 3 硬件部分 3 3 1 整体架构 3 3 2 stm32部分 3 3
  • 短视频去水印小程序源码 附带详细搭建教程

    开发语言 PHP 数据库 MySQL 无需授权 文件完全开源 可以二次开发 后台可以自己添加自己的接口 压缩包里包含一个免费 接口 不敢保证能一直使用 下载地址
  • 慌的一批!妹子一个rm -rf把公司服务器数据删没了...

    来源 https www cnblogs com zhouyu629 p 3734494 html 作者 zhouyu 责编 linse 经历了两天不懈努力 终于恢复了一次误操作删除的生产服务器数据 对本次事故过程和解决办法记录在此 警醒自
  • mysql字符串函数

    mysql的字符串函数 对于针对字符串位置的操作 第一个位置被标记为1 1 ASCII str 返回字符串str的最左面字符的ASCII代码值 如果 str是空字符串 返回 0 如果 str是 NULL 返回 NULL mysql gt s
  • 解决bootstrapTable动态添加的一行不会被$(“#bootstrap-table“).bootstrapTable(‘getSelections‘)获取到

    背景 业务需要bootstrapTable表格选中某一行数据 并将按钮表示为可点击状态 当选中多行或没选中数据时设置为不可点击状态 解决 a class btn btn success i class fa fa plus i 所选行下方添
  • (23)[CS13] LSTM Generating:Generating Sequences With Recurrent Neural Networks

    计划完成深度学习入门的126篇论文第二十三篇 UT的Alex Graves等领导研究通过LSTM来生成不同风格的文本和手写体handwriting ABSTRACT INTRODUCTION 摘要 本文通过对一个数据点的预测 说明了LSTM
  • Anaconda(Miniconda) 安装(Windows下)

    下载地址 https www anaconda com download or https conda io miniconda html 下载之后直接安装 可能需要设置路径 之后在cmd中输入 conda list 查看安装内容 如需要更
  • 测试用例的设计方法(七种)详细分析

    1 需求分析法 需求分析法 按照需求 设计测试用例 其中的需求分为两种 用户需求 软件需求 1 验证需求是否正确 完整 无二义性 并且逻辑一致 2 要从 黑盒 的角度 设计出充分并且必要的测试集 以保证设计和代码都能完全符合需求 2 等价类
  • 2023华为OD机试真题【数字游戏】

    题目内容 小明玩一个游戏 系统发1 n张牌 每张牌上有一个整数 第一张给小明 后n张按照发牌顺序排成连续的一行 需要小明判断 后n张牌中 是否存在连续的若干张牌 其和可以整除小明手中牌上的数字 输入描述 输入数据有多组 每组输入数据有两行
  • vue中native的用法

    vue中native的用法 官方解释 你可能想在某个组件的根元素上监听一个原生事件 可以使用 v on 的修饰符 native 举例 比如a标签可以直接绑定原生事件 如果你通过自定义封装了button标签 命名mao button 这时候绑
  • js 取数组对象的交集内容

    一 简单数组 两数组a 1 2 3 b 2 4 5 求a b数组 var a 1 2 3 var b 2 4 5 并集 var union a concat b filter function n return a indexOf n 1
  • vue3+element Plus使用el-tabs标签页,页面刷新不会到默认页(1)

    当我们使用el tabs标签页 在页面刷新后就会回到默认的那一页 如果我们想让页面停留在当前页 可以使用localStorage存储当前页的值 1 引入el tabs
  • vue cli3 性能优化实战

    性能优化 知识追寻者搞了个人站点后 心血来潮来了一波前端性能优化实战 个人站点地址 https zszxz com index 生成分析报告 在 packge json 中引入 analyz vue cli service build mo
  • 企业微信的外部联系人回调处理技巧

    一 关于设置接收事件服务器的信息 在企业微信管理后台的 客户联系 客户 页面 点开 API 小按钮 再点击 接收事件服务器 配置 进入配置页面 要求填写URL Token EncodingAESKey三个参数 URL是企业后台接收企业微信推