对接企业微信API自建应用配置企业可信IP

news2024/11/16 0:54:07

前言

        为了实现系统调用团队会议功能,组织发起企业微信会议,于是需要和企业微信做API对接。对接过程很难受,文档不清晰、没有SDK、没有技术支持甚至文档报文和实际接口报文都不匹配,只能说企业微信的API是从业以来见过的最难用的API,仅个人观点。

        在配置自建应用后,访问API接口竟然需要设置可信IP,不论是出于安全还是别的商业目的,该手段都太古老,怎奈人在屋檐下不得不低头。可是在配置时又需要域名验证等杂七杂八的问题,特此记录解决过程分享给大家。

正文

1、自信满满配置IP

        本以为打开这个页面直接输入外网IP即可,未曾想是个只读框,需要处理蓝色背景的提示信息,设置可信域名或解析加密URL

        可信域名自然没有,申请证书申请域名费时费力,测试阶段根本没必要

      

        于是选择第二个选项,文字描述很抽象,笔者也是查阅各方资料才总结出来。

        大体意思就是要在能外网访问的机器上部署一个服务,当企业微信的测试请求访问过去时,按照一定的加解密规则以及入参,返回对应的响应信息。这样企业微信才认为你这台机器是“自己人”,允许你继续配置可信IP,简直就是!@#*¥&()@!!。

2、骂骂咧咧获取信任

        一回头看自己还在屋檐下,继续低头想办法呗。首先把后两项全部选择随机获取,记录好生成的字符串,一会发布服务需要使用。接下来表演开始:

2.1、准备外网服务器

        找一台可以外网访问的机器,当然还需要一个打通的端口,在这台机器上安装Python3

2.2、获取Python项目

        按照这个GitHub地址,下载一个python项目,解压后重命名为 weworkapi_python

        https://github.com/sbzhu/weworkapi_python/archive/refs/heads/master.zip

        也可以使用指令处理:

wget https://github.com/sbzhu/weworkapi_python/archive/refs/heads/master.zip
unzip master.zip
mv weworkapi_python-master weworkapi_python

2.3、执行监听服务脚本

与上述项目同级开启命令窗,使用下述脚本触发执行,其中执行前需要替换三个参数,前两个为刚刚随机生成的,最后一个在企业信息中可以看到的企业ID。

qy_api = [
    WXBizMsgCrypt("XXXXXXX", "XXXXXXX", "XXXXXXX"), 
] #对应接受消息回调模式中的token,EncodingAESKey 和 企业信息中的企业id
#-*- encoding:utf-8 -*-
from flask import abort, request
from flask import Flask
from xml.dom.minidom import parseString
import _thread
import time
import os
import sys
sys.path.append("weworkapi_python/callback")  # 正确的模块导入路径
from WXBizMsgCrypt3 import WXBizMsgCrypt   # https://github.com/sbzhu/weworkapi_python 项目地址
app = Flask(__name__)
 
# 对应步骤4中接受消息回调模式中的URL,如域名是'www.example.com' 那么在步骤4中填入的url就为"http://www.example.com/hook_path"
@app.route('/hook_path', methods=['GET','POST']) 
def douban():
    if request.method == 'GET':
        echo_str = signature(request, 0)
        return(echo_str)
    elif request.method == 'POST':
        echo_str = signature2(request, 0)
        return(echo_str)
 
qy_api = [
    WXBizMsgCrypt("qCV0ro7W4CJQtn3RHbVwgYU5GAZ29AK", "PQzmYlT4vGP3ItW9OmvreGkkLpDS3A9jH2GsyfDtP3q", "ww7b1bc3d6d"), 
] #对应接受消息回调模式中的token,EncodingAESKey 和 企业信息中的企业id
 
# 开启消息接受模式时验证接口连通性
def signature(request, i): 
    msg_signature = request.args.get('msg_signature', '')
    timestamp = request.args.get('timestamp', '')
    nonce = request.args.get('nonce', '')
    echo_str = request.args.get('echostr', '')
    ret,sEchoStr=qy_api[i].VerifyURL(msg_signature, timestamp,nonce,echo_str)
    if (ret != 0):
        print("ERR: VerifyURL ret: " + str(ret))
        return("failed")
    else:
        return(sEchoStr)
 
# 实际接受消息
def signature2(request, i):
    msg_signature = request.args.get('msg_signature', '')
    timestamp = request.args.get('timestamp', '')
    nonce = request.args.get('nonce', '')
    data = request.data.decode('utf-8')
    ret,sMsg=qy_api[i].DecryptMsg(data,msg_signature, timestamp,nonce)
    if (ret != 0):
        print("ERR: DecryptMsg ret: " + str(ret))
        return("failed")
    else:
        with open ("/var/log/qywx.log", 'a+') as f: # 消息接收日志
            doc = parseString(sMsg)
            collection = doc.documentElement
            name_xml = collection.getElementsByTagName("FromUserName")
            msg_xml = collection.getElementsByTagName("Content")
            type_xml = collection.getElementsByTagName("MsgType")
            pic_xml = collection.getElementsByTagName("PicUrl")
            msg = ""
            name = ""
            msg_type = type_xml[0].childNodes[0].data
            if msg_type == "text": #文本消息
                name = name_xml[0].childNodes[0].data        #发送者id
                msg = msg_xml[0].childNodes[0].data          #发送的消息内容
                f.write(time.strftime('[%Y-%m-%d %H:%M:%S]') + "[ch%d] %s:%s\n" % (i, name, msg))
                _thread.start_new_thread(os.system, ("python3 command.py '%s' '%s' '%d' '%d'" % (name, msg, i, 0), )) #此处将消息进行外部业务处理
                
            elif msg_type == "image": #图片消息
                name = name_xml[0].childNodes[0].data
                pic_url = pic_xml[0].childNodes[0].data
                f.write(time.strftime('[%Y-%m-%d %H:%M:%S]') + "[ch%d] %s:图片消息\n" % (i, name))
                _thread.start_new_thread(os.system, ("python3 command.py '%s' '%s' '%d' '%d'" % (name, pic_url, i, 1), ))  #此处将消息进行外部业务处理
 
            f.close()
 
        return("ok")
 
if __name__=='__main__':
    app.run("0.0.0.0", 8066)  #本地监听端口,可自定义
#执行脚本
python wechat.py

若执行报错提示缺失依赖,按照pip3进行安装即可。

2.4、最终结果获取

执行成功后会根据token和secret生成监听服务,命令窗提示 ip:port ,其中端口可以在上述脚本中配置。

3、配置可验证的URL

将生成的信息配置到对应目录

http://公网IP地址:8066/hook_path

点击保存后即可正常配置可信IP,至此整个荒诞的信任危机解除,只能三个字形容:真无聊。

总结

        整个配置过程网上资料甚少,企业微信方也没有在线支持,只依靠社区实现网友之间的相濡以沫,如果能再给我一次机会,我一定选别的app进行对接,慎重慎重。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1923704.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

使用 Python OpenCV 创建图像到卡通转换器

https://pyseek.com/2022/07/image-to-cartoon-converter-in-python/ 一、说明 你有没有试过把自己的照片转换成卡通画?顺便说一句,这不是开玩笑。很多人喜欢把他们的照片变成卡通画并在社交媒体上分享。就连我自己也多次尝试过这种技术。有很多在线工具…

vue实现a-model弹窗拖拽移动

通过自定义拖拽指令实现 实现效果 拖动顶部,可对整个弹窗实施拖拽(如果需要拖动底部、中间内容实现拖拽,把下面的ant-modal-header对应改掉就行) 代码实现 编写自定义指令 新建一个ts / js文件,用ts举例 import V…

《财经日报》︱揭秘随身WiFi市场乱象与格行的破局之路 格行如何树立行业清流新标杆? 随身WiFi真的靠谱吗?

在移动互联网高速发展的今天,随身WiFi以其便捷性和高性价比迅速成为市场宠儿。然而,随着行业的迅速扩张,一系列乱象与套路也逐渐浮出水面:从虚假宣传到限速虚量,随身WiFi行业中的种种套路让消费者防不胜防。商家利用信…

Redis 的强大之处:为何它成为开发者的首选?

Redis 的强大之处:为何它成为开发者的首选? 1. 速度极快2. 数据类型多样3. 事务支持4. 特性丰富5、总结 💖The Begin💖点点关注,收藏不迷路💖 Redis,作为开源的内存数据结构存储系统&#xff0c…

AI办公自动化:相似照片批量智能删除

电脑中有大量手机照片,要批量删除其中相似度高的,首先得有一个分析照片相似度的算法和模型。CLIP(Contrastive Language-Image Pre-Training)模型是由OpenAI在2021年发布的一种多模态预训练神经网络,旨在通过对比学习方…

揭秘!MySQL索引背后的秘密武器:B+树为何力压跳表,独领风骚?

引出 想象一下,你正在一家巨大的图书馆工作,这里藏书百万册,读者络绎不绝,每个人都想尽快找到他们想要的书籍。图书馆的布局有两种设计方案摆在你面前: 方案A:使用传统的目录卡片系统,就像老式…

循环结构(一)——for语句【互三互三】

文章目录 🍁 引言 🍁 一、语句格式 🍁 二、语句执行过程 🍁 三、语句格式举例 🍁四、例题 👉【例1】 🚀示例代码: 👉【例2】 【方法1】 🚀示例代码: 【方法2】…

无人机运营合格证及无人机服务资质认证详解

一、运营合格证 无人机运营合格证是无人机运营单位或个人在特定区域内从事无人机运营活动的法定凭证。该证书由相关部门根据无人机运营单位的资质、技术能力和管理水平等综合因素进行审批和颁发。获得运营合格证的单位或个人需严格遵守国家相关法规和规定,确保无人…

3-2 多层感知机的从零开始实现

import torch from torch import nn from d2l import torch as d2lbatch_size 256 # 批量大小为256 train_iter, test_iter d2l.load_data_fashion_mnist(batch_size) # load进来训练集和测试集初始化模型参数 回想一下,Fashion-MNIST中的每个图像由 28 28 784…

【考研408操作系统】最容易理解的知识体系-文件管理-面向计算机管理

苏泽 “弃工从研”的路上很孤独,于是我记下了些许笔记相伴,希望能够帮助到大家 本篇内容续写上一篇的【考研408&操作系统】最容易理解的知识体系-文件管理-面向人类管理 这一篇将站在计算机如何管理好文件的角度去梳理这一章节的知识点 目录 本…

.欧拉函数.

先介绍欧拉函数: 贴一张 证明: 这里利用容斥原理来进行证明:若要求1~N当中与N互质的个数,则应在1~N当中去除N的质因数的倍数,因为既然是因数,那么一定不与N互质,既然是N的因数,那么…

初识Laravel(Laravel的项目搭建)

初识Laravel(Laravel的项目搭建) 一、项目简单搭建(laravel)1.首先我们确保使用国内的 Composer 加速镜像([加速原理](https://learnku.com/php/wikis/30594)):2.新建一个名为 Laravel 的项目&a…

gfast前端UI:基于Vue3与vue-next-admin适配手机、平板、pc 的后台开源模板

摘要 随着现代软件开发的高效化需求,一个能够快速适应不同设备、简化开发过程的前端模板变得至关重要。gfast前端UI,基于Vue3.x和vue-next-admin,致力于提供这样一个解决方案。本文将深入探讨gfast前端UI的技术栈、设计原则以及它如何适配手机…

(补充):java各种进制、原码、反码、补码和文本、图像、音频在计算机中的存储方式

文章目录 前言一、进制1 逢几进一2 常见进制在java中的表示3 进制中的转换(1)任意进制转十进制(2)十进制转其他进制二、计算机中的存储1 计算机的存储规则(文本数据)(1)ASCII码表(2)编码规则的发展演化2 计算机的存储规则(图片数据)(1)分辨率、像素(2)黑白图与灰度…

Linux 复现Docker NAT网络

Linux 复现Docker NAT网络 docker 网络的构成分为宿主机docker0网桥和为容器创建的veth 对构成。这个默认网络命名空间就是我们登陆后日常使用的命名空间 使用ifconfig命令查看到的就是默认网络命名空间,docker0就是网桥,容器会把docker0当成路由&…

linux nethogs网络监控程序(端口监控、流量监控、上传流量、下载流量、进程监控进程网络)

文章目录 Nethogs 网络监控程序详解1. 引言2. Nethogs 的安装与运行2.1 安装 Nethogs- **Debian/Ubuntu**- **Fedora**- **Arch Linux** 2.2 运行 Nethogs 3. Nethogs 的使用详解3.1 基本界面- **PID**:进程的 ID。- **用户**:运行该进程的用户。- **程序…

【Linux网络】数据链路层【上】{初识数据链路层/以太网/路由表/MAC地址表/ARP表/NAT表}

文章目录 1.初识数据链路层2.认识以太网2.0前导知识以太网帧和MAC帧CMSA/CD以太网的最小帧长限制是64字节IP层和MAC层 2.1以太网帧格式 3.预备知识计算机网络通信以太网和wifi路由表/MAC地址表/ARP表/NAT表/ACL表 用于同一种数据链路节点的两个设备之间进行信息传递。 1.初识数…

美团一面,你碰到过CPU 100%的情况吗?你是怎么处理的?

本文主要分为三部分 分析一下CPU 100%的常见原因 CPU 100%如何排查 回答这个问题的一个参考答案 CPU被打满的常见原因 1. 死循环 在实际工作中,可能每个开发都写过死循环的代码。 死循环有两种: 在 while、for、forEach 循环中的死循环。 无限递…

期末成绩单怎么单独发给家长,这个小工具超简单!

随着期末考试的落幕,老师们再次迎来了成绩处理的高峰期。传统的成绩单分发方式不仅耗时,还容易出错。但如今,有了易查分小程序,这一过程变得简便而高效。 易查分小程序,一个专为教师和家长设计的便捷工具,让…

[ruby on rails]部署时候产生ActiveRecord::PreparedStatementCacheExpired错误的原因及解决方法

一、问题: 有时在 Postgres 上部署 Rails 应用程序时,可能会看到 ActiveRecord::PreparedStatementCacheExpired 错误。仅当在部署中运行迁移时才会发生这种情况。发生这种情况是因为 Rails 利用 Postgres 的缓存准备语句(PreparedStatementCache)功能来…