77 行
2.9 KiB
JavaScript
77 行
2.9 KiB
JavaScript
const https = require('https')
|
|
const config = require('../config')
|
|
|
|
function requestJson(url) {
|
|
return new Promise((resolve, reject) => {
|
|
https.get(url, res => {
|
|
let raw = ''
|
|
res.on('data', chunk => { raw += chunk })
|
|
res.on('end', () => {
|
|
try { resolve(JSON.parse(raw)) } catch (err) { reject(err) }
|
|
})
|
|
}).on('error', reject)
|
|
})
|
|
}
|
|
|
|
function postJson(url, body) {
|
|
return new Promise((resolve, reject) => {
|
|
const data = JSON.stringify(body || {})
|
|
const req = https.request(url, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'Content-Length': Buffer.byteLength(data)
|
|
}
|
|
}, res => {
|
|
let raw = ''
|
|
res.on('data', chunk => { raw += chunk })
|
|
res.on('end', () => {
|
|
try { resolve(JSON.parse(raw)) } catch (err) { reject(err) }
|
|
})
|
|
})
|
|
req.on('error', reject)
|
|
req.write(data)
|
|
req.end()
|
|
})
|
|
}
|
|
|
|
let accessTokenCache = null
|
|
|
|
async function getAccessToken() {
|
|
if (accessTokenCache && accessTokenCache.expiresAt > Date.now() + 60000) return accessTokenCache.token
|
|
if (!config.wechat.appid || !config.wechat.secret) throw new Error('WECHAT_APPID or WECHAT_SECRET is not configured')
|
|
const url = 'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=' + encodeURIComponent(config.wechat.appid) + '&secret=' + encodeURIComponent(config.wechat.secret)
|
|
const data = await requestJson(url)
|
|
if (!data.access_token) throw new Error(data.errmsg || 'wechat access_token failed')
|
|
accessTokenCache = {
|
|
token: data.access_token,
|
|
expiresAt: Date.now() + (Number(data.expires_in || 7200) * 1000)
|
|
}
|
|
return accessTokenCache.token
|
|
}
|
|
|
|
async function code2Session(code) {
|
|
if (config.nodeEnv === 'development' && (!code || code === 'local' || String(code).indexOf('dev_') === 0)) {
|
|
return { openid: 'dev_openid_' + String(code || 'local').slice(-8) }
|
|
}
|
|
if (!config.wechat.appid || !config.wechat.secret) {
|
|
if (config.nodeEnv === 'development') return { openid: 'dev_openid_' + String(code || 'local').slice(-8) }
|
|
throw new Error('WECHAT_APPID or WECHAT_SECRET is not configured')
|
|
}
|
|
const url = 'https://api.weixin.qq.com/sns/jscode2session?appid=' + encodeURIComponent(config.wechat.appid) + '&secret=' + encodeURIComponent(config.wechat.secret) + '&js_code=' + encodeURIComponent(code) + '&grant_type=authorization_code'
|
|
const data = await requestJson(url)
|
|
if (!data.openid) throw new Error(data.errmsg || 'wechat login failed')
|
|
return data
|
|
}
|
|
|
|
async function getPhoneNumber(code) {
|
|
if (!code) throw new Error('phone code required')
|
|
const token = await getAccessToken()
|
|
const url = 'https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=' + encodeURIComponent(token)
|
|
const data = await postJson(url, { code })
|
|
if (data.errcode) throw new Error(data.errmsg || 'get phone number failed')
|
|
return data.phone_info || null
|
|
}
|
|
|
|
module.exports = { code2Session, getPhoneNumber }
|