zoukankan      html  css  js  c++  java
  • 企业微信第三方应用配置(附接口示意代码)

    企业微信第三方应用配置

    TIPS:在我开发之前,在网上找的文档之类的,都是说应用要在套件下创建,但是企业微信已经取消了这个套件,直接就是应用了

    创建应用

    前期配置

    • 想要发布第三方应用,首先要注册成微信服务商
    • 完善品牌、官网等信息,提交申请。注:品牌下可以有多个应用,目前企业微信已取消了,套件这个东西
    • 登录服务商应用后台 -> 标准应用服务 -> 本地应用 -> 创建应用(创建应用配置分基础信息和开发信息,开发信息是重头戏)

    开发配置

    捡了一此主要的配置来写:

    • 应用主页:这个是在工作台点击应用后,直接跳转的页面。这个url中支持$CORPID$,这个会转换成打开应用的企业的corpid,前端获得这个参数,传给后台处理得到签名(如果想使用jsapi的功能的话)。
    • 可信域名:这个就是填写你的网站的域名即可
    • 数据回调URL指令回调URL:这两个在创建应用的时候,微信服务器都会发送一个校验,这个是官网教的处理方法。从校验的角度来说这两个接口是一样的。但是功能上是有区别的。
      • 数据回调URL:这个是第三方应用创建完成后,接收企业信息的。这个URL中支持和应用主页一样的$CORPID$参数,来区分是哪个企业发来的信息
      • 指令回调URL:这个作用比较大,是接收一些授权信息ticket参数

    说明:这两个回调URL在验证的时候是GET请求,在业务处理上是POST请求。
    所以写下来代码结构应该是这样的

    获取到永久授权码和corpid之后,需要存到数据库中

    最后在使用的时候就是这么个过程

    1. 前端请求后台接口,获取签名,携带参数为corpid,这个值前端可以从应用主页的url中就可以获取。另一个参数是当前页面的url用于后台生成签名。
    2. 后台接收corpid后从数据库中查询出该企业的永久授权码,再结合推送到指令回调的ticket,三个参数去获取access_token详情
    3. 使用上步获取的access_token来获取jsapi_ticket详情
    4. 使用jsapi_ticketurl和随机字符串和时间戳四个参数,去生成签名,详情
    5. 最后返回前端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');
    
  • 相关阅读:
    IOS、java支持DES加密
    多线程——@synchronized(object)
    LSM树存储模型
    System.setProperty()
    Filter及FilterChain的使用具体解释
    Java有用经验总结--Swing篇
    POJ3342——Party at Hali-Bula
    Hadoop-2.4.1学习之Writable及事实上现
    OpenCV 编程简单介绍(矩阵/图像/视频的基本读写操作)
    Android中Context具体解释 ---- 你所不知道的Context
  • 原文地址:https://www.cnblogs.com/changzhenan/p/8489952.html
Copyright © 2011-2022 走看看