node 微信公众号开发(四)—— 获取并缓存 jsapi_ticket 并生成 JS-SDK 权限验证的签名

  最近想用 node 写一个微信公众号的项目,建议全程 https,这里记录一下如何获取并缓存 jsapi_ticket 并生成 JS-SDK 权限验证的签名。

一、jsapi_ticket

  这一部分可参考 官方文档 - JS-SDK 使用权限签名算法app.config.js

1、getJsapiTicket.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
/**
* jsapiTicket 的缓存和更新
*/
const fs = require('fs')
const path = require('path')
const request = require('request')
const appConfig = require('../../app.config')

const fileName = path.resolve(__dirname, './jsapiTicket.json')
let accessTokenTemp, validTime = 7200 // jsapiTicket 的默认有效时间

/**
* 根据 access_token 获取 jsapiTicket
* @param {string} accessToken
*/
const getJsapiTicket = async (accessToken) => {
accessTokenTemp = accessToken
try {
let readRes = fs.readFileSync(fileName, 'utf8')
readRes = JSON.parse(readRes)

// 如果创建的时间超过现在时间默认 7200ms
const createTime = new Date(readRes.createTime).getTime()
const nowTime = new Date().getTime()
if ((nowTime - createTime) / 1000 >= validTime) {
await updateJsapiTicket()
return await getJsapiTicket()
}

return readRes.jsapiTicket
} catch (error) {
// 未读取到文件中的正确内容则更新接口
await updateJsapiTicket()
return await getJsapiTicket()
}
}

// 更新本地缓存的 jsapiTicket
const updateJsapiTicket = async () => {
const res = JSON.parse(await getNewJsapiTicket())
if (res.ticket) {
validTime = res.expires_in
fs.writeFileSync(fileName, JSON.stringify({ createTime: new Date(), ...res }))
} else {
await updateJsapiTicket()
}
}


/**
* 根据 access_token 获取 jsapiTicket
* @return {Promise}
*/
// 从微信获取新的 jsapiTicket,有效时间默认是 7200ms
const getNewJsapiTicket = async () => {
console.log('从微信服务器获取 jsapiTicket 啦')
return new Promise((resolve, reject) => {
request.get(`${ appConfig.wxapiBaseUrl }/ticket/getticket?access_token=${ accessTokenTemp }&type=jsapi`, (err, res, body) => {
if (err) {
reject('获取 jsapiTicket 失败 检查 getJsapiTicket 函数')
}
resolve(body)
})
})
}

// jsapiTicket 默认有效时间 7200ms,五分钟交替时间
setInterval(async () => {
await updateJsapiTicket()
}, (validTime - 300) * 1000)

module.exports = getJsapiTicket

2、外部获取 jsapi_ticket

1
2
3
4
5
const getAccessToken = require('../utils/wechat/getAccessToken')
const getJsapiTicket = require('../utils/wechat/getJsapiTicket')

const jsapiTicket = await getJsapiTicket(await getAccessToken())
console.log(jsapiTicket)

二、签名算法

  这一部分可参考 官方文档 - JS-SDK 使用权限签名算法

1、sign.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
/**
* 从这里下载官方示例
* http://demo.open.weixin.qq.com/jssdk/sample.zip
* jssha 请用官方示例中的文件
*/

var createNonceStr = function () {
return Math.random().toString(36).substr(2, 15)
}

var createTimestamp = function () {
return parseInt(new Date().getTime() / 1000) + ''
}

var raw = function (args) {
var keys = Object.keys(args)
keys = keys.sort()
var newArgs = {}
keys.forEach(function (key) {
newArgs[key.toLowerCase()] = args[key]
})

var string = ''
for (var k in newArgs) {
string += '&' + k + '=' + newArgs[k]
}
string = string.substr(1)
return string
}

/**
* @synopsis 签名算法
*
* @param appId 应用appId
* @param jsapi_ticket 用于签名的 jsapi_ticket
* @param url 用于签名的 url ,注意必须动态获取,不能 hardcode
*
* @returns
*/
var sign = function (appId, jsapi_ticket, url) {
let timestamp = createTimestamp()
let nonceStr = createNonceStr()
var ret = { appId, jsapi_ticket, nonceStr, timestamp, url }
var string = raw(ret)
var jsSHA = require('jssha')
var shaObj = new jsSHA(string, 'TEXT')
var signature = shaObj.getHash('SHA-1', 'HEX')

const config = { appId, timestamp, nonceStr, signature }
return config
}

module.exports = sign

注意
jssha 建议与官方 demo 使用的版本一致,即1.5.0版本,可输入如下命令安装:

1
npm i jssha@1.5.0 -S

2、签名结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const appConfig = require('../app.config')
const sign = require('../utils/wechat/sign')
const getAccessToken = require('../utils/wechat/getAccessToken')
const getJsapiTicket = require('../utils/wechat/getJsapiTicket')

// 获取微信鉴权信息
async getConfig () {
let config
try {
const jsapiTicket = await getJsapiTicket(await getAccessToken())
config = sign(appConfig.appId, jsapiTicket, ctx.query.url)
} catch (error) {
console.log('error', error)
config = {}
}
console.log(config)
}
以上

随笔标题:node 微信公众号开发(四)—— 获取并缓存 jsapi_ticket 并生成 JS-SDK 权限验证的签名

随笔作者:刘先玉

发布时间:2020年12月11日 - 11:43:35

最后更新:2020年12月11日 - 11:43:35

原文链接:https://liuxianyu.cn/article/node-wechat-jsapi_ticket.html