企业微信获取第三方应用凭证

上一篇介绍了如何配置通用开发参数及通过url回调验证,

本篇将通过服务商后台配置关联小程序应用配置和获取第三方凭证及如何配置企业可信IP。

当然上篇配置的回调设置也不会白费,在下方的指令和数据回调会用到。

第三方应用开发流程

官方企业微信第三方应用开发的基本流程如下:

小程序应用设置

获取suite_ticket需要使用SuiteID参数,因为项目使用的是三方应用方式开发,

这里可以通过设置小程序->关联小程序详情。

前面的配置基础信息与应用权限不在介绍,比较简单。

配置内容描述

应用主页:必填,用户从企业微信工作台进入应用时将直接跳转到对应主页URL

桌面端独立主页:用户从企业微信桌面端工作台进入应用时跳转的应用页面URL

可信域名:仅支持可信域名内的应用调用OAuth2授权、JSSDK等

安装完成回调域名:用户安装成功后可指定跳转至该域名的链接

业务设置URL:授权企业的管理员可从企业微信后台的应用详情页免登录直接跳转该链接进行应用配置。

数据回调URL:必填,用于正确响应企业微信验证URL的请求,用于接收托管企业微信应用的用户信息、进入应用事件、通讯录变更事件。

指令回调URL:必填,用户正确响应企业微信验证URL的请求,用于接收应用(添加、删除、修改)以及ticket参数等API请求。

Secret是可以生成和改变的,SuiteID是系统生成的。

配置可信域名

配置可信域名:先填写网站域名,不要写http或者https前缀,直接是网站域名。

如下:

具体怎么验证可信域名呢,接着点击检验可信域名归属:

需要把这个文件下载后,上传到网站域名下,并且可以访问到;

放好之后,如果验证不成功,可能有缓存,等待几分钟在尝试。

设置回调配置

这几项就关于回调的参数, 之前配置过url/token/encodingAESKey直接再粘贴过来即可。

指令回调和数据回调地址可以写上篇完成的回调地址,只是要注意现在的token和EncodingAESKey换成之前调好的token和EncodingAESKey和字符串就行或者也可以把代码中的这两项换成现在新生成的。

这些可以分步配置,最后保存完成后,效果如下图:

如果暂时不知道设置项是什么作用,可以先配置一个,之后用上了再改即可。

获取ticket

设置好应用参数后,把suiteID、secret粘贴一下,在代码中要使用。

控制器接收参数

这里因为一开始不确定参数情况,所以对接收的所有参数存储到日志中。

首先判断请求方式为post,然后具体进入接收数据环节。

经过多次调试后确定需要接收四个参数内容,其中msg_signature/timestamp/nonce三个可直接通过字段名获取到,比较麻烦的是密文数据,需要使用php://input获取。

内容是一个xml格式的字符串。

内容如下:

public function wxNotify()
{
    $obj = new CompanyWxPushService();
    $all = request()->all();
    writeRecordLog('companyWechat.log', request()->method());
    writeRecordLog('companyWechat.log', var_export($all, true));
    if (request()->isMethod('POST')) {
        $msg_signature = request()->input('msg_signature');
        $timeStamp = request()->input('timestamp');
        $nonce = request()->input('nonce');
        // post请求的密文数据
        $sReqData = file_get_contents('php://input');
        echo $obj->callbackPOST($msg_signature, $timeStamp, $nonce, $sReqData);
    }  die();
}

业务层解析

下面的处理中思路是:收到post请求之后

1.解析出url上的参数,包括消息体签名(msg_signature),时间戳(timestamp)以及随机数字串(nonce);

2.验证消息体签名的正确性。

3.将post请求的数据进行xml解析,并将<Encrypt>标签的内容进行解密,

解密出来的明文是xml格式的字符串需要转变为xml对象。

4.判断对象的infotype获取suite_ticket并进行存储,之后调用access_token需要使用。

内容如下:

class CompanyWxPushService
{
    //  接收信息时的加解密参数
    protected static $encodingAesKey = "随机生成的encodingAESKey";

    // 接收信息时的校验Token
    protected static $token = "随机生成的token";

    protected static $corpId = "服务商注册后获取的corpID";


    protected static $SuiteID = '小程序应用详情获取的suiteID';

    protected static $Secret = '小程序应用详情获取的secret';

    /**
     * 企业微信post回调解析
     * @param $sReqMsgSig
     * @param $sReqTimeStamp
     * @param $sReqNonce
     * @param $sReqData
     * @return string
     */
    public function callbackPOST($sReqMsgSig, $sReqTimeStamp, $sReqNonce, $sReqData)
    {
        $sMsg = "";  // 解析之后的明文
        $wxcpt = new \WXBizMsgCrypt(self::$token, self::$encodingAesKey, self::$SuiteID);
        $errCode = $wxcpt->DecryptMsg($sReqMsgSig, $sReqTimeStamp, $sReqNonce, $sReqData, $sMsg);
        writeRecordLog('companyWechat.log', $errCode);
        if ($errCode == 0) {
            // 解密成功,sMsg即为xml格式的明文
            writeRecordLog('companyWechat.log', "解密成功:\r\n". var_export($sMsg, true));
            // TODO: 对明文的处理
            // 解析该xml字符串,利用simpleXML
            libxml_disable_entity_loader(true);
            //禁止xml实体解析,防止xml注入
            $xml = simplexml_load_string($sMsg, 'SimpleXMLElement', LIBXML_NOCDATA);
            switch ($xml->InfoType) {
                case 'suite_ticket': // 存储suite_ticket
                    $log_desc = '存储suite_ticket:' . $xml->SuiteTicket;
		  self::$redisWechat->setCompanyTicket($xml->SuiteTicket);
                    break;
                default:
                    $log_desc = '未知的类型:' . $xml->InfoType;
                    break;
            }
            writeRecordLog('companyWechat.log', '解析日志:' . $log_desc);
            return 'success';
        } else {
            return "ERR: " . $errCode . "\n\n";
        }
    }
}

获取ticket

企业微信服务器会定时(每十分钟)向指令回调 URL 推送 suite_ticket,在指令回调的后台逻辑中解密消息体即可得到对应的 InfoType 和 SuiteTicket 。

不同类型的指令回调会通过不同的 InfoType 进行区分,在每次解密得到 suite_ticket 后,应在服务端临时缓存起来。

也可通过刷新ticket按钮来多次快速获取验证解析。

日志情况如下:

获取 suite_access_token

获取suite_access_token即为获取第三方凭证,这个在整个开发中很重要,接下来的几个接口都需要三方凭证;在成功接受并且缓存 suite_ticket 之后,我们可以主动来获取 suite_access_token。获取suite_access_token时,需要 suite_id,suite_secret suite_ticket 作为参数。

请求方式

POST

请求地址

https://qyapi.weixin.qq.com/cgi-bin/service/get_suite_token

参数说明

参数

是否必须

说明

suite_id

第三方应用id或者代开发应用模板id。第三方应用以ww或wx开头应用id(对应于旧的以tj开头的套件id);代开发应用以dk开头

suite_secret

第三方应用secret 或者代开发应用模板secret

suite_ticket

企业微信后台推送的ticket,即回调中获取的ticket

控制器

暂时先写一个请求,看一下返回内容。

/**
 * 获取企业微信 suite_access_token
 */
public function companyAccessToken()
{
    $obj = new CompanyWxPushService();
    print_r($obj->companyAccessToken());die;
}

业务层处理

需要三方应用SuiteID和Secret参数和之前回调返回中解密后获取的suite_ticket。

Suite_ticket这一步是通过回调获取的suite_ticket内容,设置的redis缓存。

/**
 * 获取企业微信 suite_access_token
 * @return bool|string
 */
public function companyAccessToken()
{
    $url = "https://qyapi.weixin.qq.com/cgi-bin/service/get_suite_token";
    $params = [
        'suite_id' => self::$SuiteID,
        'suite_secret' => self::$Secret,
        'suite_ticket' => self::$redisWechat->getCompanyTicket()
    ];
    return $this->linkCurl($url, 'POST', $params);
}

/**
 * 请求接口返回内容
 * @param $url : 请求的URL地址
 * @param $method : 请求方式POST|GET
 * @param bool $params : 请求的参数
 * @return bool|string
 */
protected function linkCurl($url, $method, $params = false)
{
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_FAILONERROR, false);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    if (strpos("$" . $url, "https://") == 1) {
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
    }
    curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 60);
    curl_setopt($ch, CURLOPT_TIMEOUT, 60);
    if ($method == "POST") {
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, json($params));
    } else if ($params) {
        curl_setopt($ch, CURLOPT_URL, $url . '?' . http_build_query($params));
    }
    $response = curl_exec($ch);
    if ($response === FALSE) return false;

    curl_close($ch);
    return $response;
}

响应:

{"errcode":60020,"errmsg":"not allow to access from your ip:client ip 123......."}

怀疑是没注册应用和配置企业可信ip。

响应60020是未设置IP白名单,可查看下方第三方应用企业可信IP设置。

设置后,再次请求返回正常。

{"suite_access_token":"tpBubbmIlo_N5zoCKXvz_9q6IanamtrZMB2rBI_Mnh48m9Fqwr7dwak3QZZPJA5O7KBQ_736ks3yogBT5djZerXrajnDUk9hsvP2xGVMnJSq1jPKDvlzIbayUoIX3lCr","expires_in":7200}

 

响应参数描述

参数

是否必须

说明

suite_id

第三方应用id或者代开发应用模板id。第三方应用以ww或wx开头应用id(对应于旧的以tj开头的套件id);代开发应用以dk开头

suite_secret

第三方应用secret 或者代开发应用模板secret

suite_ticket

企业微信后台推送的ticket

 

企业可信IP设置

第三方应用或待开发应用需要在服务商后台->服务商信息->基本信息

中设置ip白名单;1分钟后生效。

设置白名单

注意:一般员工账号看不到,需要切换管理员账号。

总结

通过第三方应用开发流程可以知道获取第三方凭证suite_access_token的原因,在之后的API中是一个很重要的参数;在获取的途中,因为不熟悉遇到设置白名单的问题,权限是普通权限看不到服务商功能,之后才发现是权限问题,希望其他开发者不会有这个困惑。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

v-for 循环数组的某一部分

方法一&#xff1a;使用slice()方法 代码&#xff1a; <template><div><!--循环前三个元素--><span v-for"(item, index) in arr.slice(0, 3)" :key"index a">{{ item }}</span> <br><!--循环前第六个到第九个元…

语义检索系统【全】:基于milvus语义检索系统指令全流程-快速部署版

搜索推荐系统专栏简介:搜索推荐全流程讲解(召回粗排精排重排混排)、系统架构、常见问题、算法项目实战总结、技术细节以及项目实战(含码源) 专栏详细介绍:搜索推荐系统专栏简介:搜索推荐全流程讲解(召回粗排精排重排混排)、系统架构、常见问题、算法项目实战总结、技术…

【Android】带下划线的TextView

序言 我们有时候需要一个类似这样的显示&#xff0c;上面是文字&#xff0c;下面是一条线 这样的显示效果是TextView实现不了的&#xff0c;需要我们自己进行修改一下。 实现 创建一个UnderlineTextView&#xff0c;继承系统的TextView class UnderlineTextView(mContext…

LeetCode(23)找出字符串中第一个匹配项的下标【数组/字符串】【简单】

目录 1.题目2.答案3.提交结果截图 链接&#xff1a; 找出字符串中第一个匹配项的下标 1.题目 给你两个字符串 haystack 和 needle &#xff0c;请你在 haystack 字符串中找出 needle 字符串的第一个匹配项的下标&#xff08;下标从 0 开始&#xff09;。如果 needle 不是 hays…

如何选择适合企业的ERP管理系统

如何选择适合企业的ERP管理系统&#xff1f; 企业业务不断发展和扩大&#xff0c;ERP管理系统已成为企业实现信息化管理、提高工作效率、降低成本的重要工具。然而&#xff0c;市场上ERP管理系统种类繁多&#xff0c;如何选择适合自己企业的ERP管理系统成为了企业面临的难题。本…

大力说企微第一课:企业微信的注册验证和认证

这段时间有好几个朋友问我&#xff0c;怎么用企业微信&#xff0c;还有一些朋友反馈&#xff0c;企业微信使用起来不太方便。 在我的印象中&#xff0c;企业微信确实不如微信那么简单&#xff0c;毕竟用户对象是企业&#xff0c;是企业就有多个部门&#xff0c;就有流程&#x…

自律成就未来:中国人民大学与加拿大女王大学金融硕士项目引领金融精英之路

在这个日新月异的时代&#xff0c;金融行业正以前所未有的速度发展&#xff0c;对金融人才的需求也日益增长。为了培养更多具备专业素养、创新精神和国际视野的金融精英&#xff0c;中国人民大学与加拿大女王大学金融硕士项目应运而生&#xff0c;致力于为学员提供一个全面提升…

如何构建风险矩阵?3大注意事项

风险矩阵法&#xff08;RMA&#xff09;是确定威胁优先级别的最有效工具之一&#xff0c;可以帮助项目团队识别和评估项目中的风险&#xff0c;帮助项目团队对风险进行排序&#xff0c;清晰地展示风险的可能性和严重性&#xff0c;为项目团队制定风险管理策略提供依据。 如果没…

车联网解决方案(车联网设备安装部署案例)

车联网&#xff08;Connected Car&#xff09;是指通过无线通信技术将汽车与互联网连接起来&#xff0c;实现车辆与车辆之间、车辆与道路基础设施之间以及车辆与互联网之间的信息交流和实时控制。车载网关是车联网系统中的核心设备之一&#xff0c;负责将车辆内部的数据传输到云…

[msg_msg] corCTF2021 -- fire_of_salvation

前言 msg_msg 是 kernel pwn 中经常用作堆喷的结构体. 其包含一个 0x30 大小的 header. 但 msg_msg 的威力远不如此, 利用 msg_msg 配合其他堆漏洞可以实现任意地址读写的功能. 程序分析 本题给了源码, 可以直接对着源码看. 并且题目给了编译配置文件, 所以可以直接编译一个…

vue部署之后提示用户更新的两种方式(http请求和worker线程请求)

const { writeFile, mkdir, existsSync } require(fs) // 动态生成版本号 const createVersion () > {// mkdir(./dist, { recursive: true }, (err) > {//检测dist目录是否存在if (existsSync(./dist)) {writeFile(./dist/version.json, {"version":"$…

MatrixOne 支持多样化生态工具,持续提升开发者体验

概述 在选择一款数据库产品时&#xff0c;对数据库上下游生态组件的打通是大数据开发工程师需要面对的一致难题。 MatrixOne提出了“One Size Fits Most”理念&#xff0c;旨在用全新HSTAP技术架构打破数据孤岛&#xff0c;其中&#xff0c;与各生态组件的“无缝衔接”也是Ma…

二维码智慧门牌管理系统升级解决方案:高效服务审核流程

文章目录 前言一、服务审核流程优化二、创新性解决方案 前言 随着科技的不断发展&#xff0c;智能化管理已经广泛渗透到社会各个领域。在这一趋势下&#xff0c;二维码智慧门牌管理系统成为服务行业中应用广泛的工具。为了更好地满足用户需求、提升服务质量和效率&#xff0c;…

【数据下载】FileZilla安装及使用说明:以全球NCEP 再分析数据集为例

1 简介# 1 简介 FileZilla是一个免费开源的FTP软件&#xff0c;分为客户端版本和服务器版本&#xff0c;具备所有的FTP软件功能。 1.1 下载地址 File Zilla官网下载 1.2 安装过程 下载完成后&#xff0c;界面如下&#xff1a; 2 使用 2.1 主机设置 2.2 下载数据 全球N…

Git相关: 拉取、git push提交 过程遇到的错误

目录 解决git push报错error: RPC failed; HTTP 413 curl 22 关于这个问题&#xff0c;其实千万别用gitlab,因为你怎么推送 也不可能把几G的文件推上去。 error: RPC failed; HTTP 413 curl 22 The requested URL returned error: 413 se 解决git push报错error: RPC failed;…

腾讯云服务器可用区是什么?随机可用区选择方法

腾讯云服务器可用区是什么意思&#xff1f;云服务器可用区如何选择&#xff1f;可用区是指在同一个地域内电力和网络相互独立的区域&#xff0c;可用区可以做到故障隔离&#xff0c;所以可用区存在的意义在于构建高可用、高容灾应用&#xff0c;将应用部署在不同可用区内&#…

TCP协议通讯流程

文章目录&#xff1a; 通讯流程全过程浏览建立连接过程数据传输过程断开连接问题 通讯流程全过程浏览 下图是基于TCP协议的客户端/服务器程序的一般流程&#xff1a; 上图就是TCP协议的通信流程&#xff0c;接下来认识初步认识以下TCP建立连接&#xff08;三次握手&#xff0…

React函数组件状态Hook—useState《进阶-对象数组》

React函数组件状态-state 对象 state state 中可以保存任意类型的 JavaScript 值&#xff0c;包括对象。但是&#xff0c;你不应该直接修改存放在 React state 中的对象。相反&#xff0c;当你想要更新⼀个对象时&#xff0c;你需要创建⼀个新的对象&#xff08;或者将其拷⻉⼀…

(C++)栈的链式存储结构(出栈、入栈、判空、遍历、销毁)(数据结构与算法)

链栈是运算受限的单链表、只能在链表头部进行操作 1.链表的头指针就是栈顶,链头为栈顶&#xff0c;链尾为栈底 2.栈的链式存储不需要附设头节点 3.基本不存在栈满的情况,不需要判断栈满&#xff0c;但要判空 4.空栈相当于头指针指向空 5.插入和删除仅在栈顶处执行 6.因为是动态…

ncbi-datasets-cli-高效便捷下载NCBI数据

文章目录 简介安装datasets download下载基因组/基因序列按照GCA list文件编号下载下载大基因组genome完整参数gene参数 datasets summary下载元数据dataformat将json转换成表格格式通过json文件解析其他字段问题 简介 NCBI Datasets 可以轻松从 NCBI 数据库中收集数据。使用命…