企业微信第三方应用配置
TIPS:在我开发之前,在网上找的文档之类的,都是说应用要在套件下创建,但是企业微信已经取消了这个套件,直接就是应用了
创建应用
前期配置
- 想要发布第三方应用,首先要注册成微信服务商
- 完善品牌、官网等信息,提交申请。注:品牌下可以有多个应用,目前企业微信已取消了,套件这个东西
- 登录服务商应用后台 -> 标准应用服务 -> 本地应用 -> 创建应用(创建应用配置分基础信息和开发信息,开发信息是重头戏)
开发配置
捡了一此主要的配置来写:
- 应用主页:这个是在工作台点击应用后,直接跳转的页面。这个url中支持
$CORPID$
,这个会转换成打开应用的企业的corpid
,前端获得这个参数,传给后台处理得到签名(如果想使用jsapi的功能的话)。 - 可信域名:这个就是填写你的网站的域名即可
- 数据回调URL和指令回调URL:这两个在创建应用的时候,微信服务器都会发送一个校验,这个是官网教的处理方法。从校验的角度来说这两个接口是一样的。但是功能上是有区别的。
- 数据回调URL:这个是第三方应用创建完成后,接收企业信息的。这个URL中支持和应用主页一样的
$CORPID$
参数,来区分是哪个企业发来的信息 - 指令回调URL:这个作用比较大,是接收一些授权信息和ticket参数
- 数据回调URL:这个是第三方应用创建完成后,接收企业信息的。这个URL中支持和应用主页一样的
说明:这两个回调URL在验证的时候是GET
请求,在业务处理上是POST
请求。
所以写下来代码结构应该是这样的
获取到永久授权码和corpid之后,需要存到数据库中
最后在使用的时候就是这么个过程
- 前端请求后台接口,获取签名,携带参数为
corpid
,这个值前端可以从应用主页的url中就可以获取。另一个参数是当前页面的url
用于后台生成签名。 - 后台接收
corpid
后从数据库中查询出该企业的永久授权码,再结合推送到指令回调的ticket
,三个参数去获取access_token
,详情 - 使用上步获取的
access_token
来获取jsapi_ticket
,详情 - 使用
jsapi_ticket
和url
和随机字符串和时间戳四个参数,去生成签名,详情 - 最后返回前端3个参数,即:签名+生成签名的随机字符串+生成签名的时间戳
前端拿到参数后,进行wx.config
配置后就可以愉快地使用wx的api了。
接口业务代码
只是示意,没写过后台代码
const Express = require('express');
const app = Express();
const bodyParser = require('body-parser');
require('body-parser-xml')(bodyParser);
const axios = require('axios');
app.use(bodyParser.xml());
let ticketCount = 0; // 推送ticket计数器
let suite_access_token = ''; // 全局的suite_access_token,getSuiteAccessToken调用成功后会更新一次
/**
* getSuiteAccessToken:获取suite_access_token
* @param:
* ticket[string]:由指令接口接收到
* */
function getSuiteAccessToken(ticket) {
let data = {
suite_id: 'xxx', // 固定值
suite_secret: 'yyy', // 固定值
suite_ticket: ticket
};
axios.post('https://qyapi.weixin.qq.com/cgi-bin/service/get_suite_token', data).then(result => {
suite_access_token = result.body.suite_access_token;
ticketCount = 0;
}).catch(error => {
console.log(error);
// 获取失败,再次获取
getSuiteAccessToken(ticket);
});
}
/**
* getPermanentCode:获取永久授权码
* @param:
* createAuth:临时授权码
* */
function getPermanentCode(createAuth) {
let data = {auth_code: createAuth};
axios.post('https://qyapi.weixin.qq.com/cgi-bin/service/get_permanent_code?suite_access_token=' + suite_access_token, data).then(result => {
// 请求永久授权码成功,连接数据库,将企业corpid和永久授权码等信息保存至数据库
});
}
/**
* getAccessToken:根据corpid获取accesstoken
* */
function getAccessToken(corpid) {
// 同样,获取jsApiTicket的AccessToken也是7200s的有效期,也保存到数据库中
// 先查询,如果没有,或者过期 就重新执行一次请求accessToken的过程
return new Promise(async function(resolve, reject) {
let accessToken = 'accessToken'; // 查询
let accessTokenExpiresTime = 'xxx'; // 查询
let isOverdue = new Data() - accessTokenExpiresTime > 7200 * 1000;
if (accessToken && !isOverdue) {
resolve(accessToken);
} else {
let data = {
auth_corpid: corpid,
permanent_code: 'permanent_code' // 需要查询
};
axios.post('https://qyapi.weixin.qq.com/cgi-bin/service/get_corp_token?suite_access_token=' + suite_access_token, data).then(result => {
resolve(result.data.access_token);
});
}
});
}
/**
* getJsApiTicket:获取jsapi ticket
* @param:
* corpid[string]:企业id
* @return:
* ticket[string]:
* */
function getJsApiTicket(corpid) {
// 一个企业的jsApiTicket保存时间为7200s 获得之后就保存到数据库中,有一个字段jsApiTicketExpiresTime记录一下过期时间
// 先从数据库中根据corpid取值,如果没有或者过期则重新请求一次
return new Promise(async function(resolve, reject) {
let jsApiTicket = 'ticket'; // 数据库中查询
let jsApiTicketExpiresTime = 'xxx'; // 数据库中查询
let isOverdue = new Data() - jsApiTicketExpiresTime > 7200 * 1000;
// 没有过期并且存在就使用这个
if (jsApiTicket && !isOverdue) {
resolve(jsApiTicket);
} else {
let accessToken = await getAccessToken();
axios.get('https://qyapi.weixin.qq.com/cgi-bin/get_jsapi_ticket?access_token=' + accessToken).then(result => {
resolve(result.data.ticket);
});
}
});
}
/**
* getSign:生成签名算法
* */
function getSign() {
// 生成签名算法
}
// 校验接口
app.get('/verify', function (req, res) {
// 创建应用的校验过程
});
// 指令校验接口
app.get('/orderUrl', function (req, res) {
// 转发到 /verify 接口
});
// 数据校验接口
app.get('/dataUrl', function (req, res) {
// 转发到 /verify 接口
});
// 指令接口 可以获取ticket和AuthCode
app.post('/orderUrl', function (req, res) {
// 获取数据类型
let infoType = req.body.InfoType;
if (infoType === 'create_auth') {
// 企业推送授权信息
let authCode = req.body.AuthCode;
getPermanentCode(authCode);
} else if (infoType === 'suite_ticket') {
// 微信后台推送 ticket
ticketCount++;
if (ticketCount >= 10) {
// 10min推送一次,计10次,执行一次获取suite_access_token请求
let ticket = req.body.SuiteTicket;
getSuiteAccessToken(ticket);
}
}
res.send('success');
});
app.get('/sign', async function (req, res) {
let corpid = req.query.corpid;
let url = req.query.url;
let jsApiTicket = await getJsApiTicket(corpid);
let noncestr = 'Wm3WZYTPz0wzccnW'; // 随机生成
let timestamp = 1414587457; // 时间戳
// 根据4个参数生成签名
let sign = getSign(jsApiTicket, url, noncestr, timestamp);
res.send({
sign,
noncestr,
timestamp
});
});
app.listen('8001');