You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

134 lines
3.3 KiB

3 years ago
  1. 'use strict';
  2. /**
  3. * 微信相关业务
  4. */
  5. const {
  6. wxConfigMp,
  7. wxConfigApp,
  8. } = require('config')
  9. const crypto = require('crypto')
  10. const db = uniCloud.database();
  11. /**
  12. * 微信小程序授权登录获取session_key
  13. * @param {Object} options
  14. * @param {String} options.code 小程序code
  15. *
  16. * @param {String} options.encryptedData 可选存在encryptedData和iv时返回用户信息包含unionid
  17. * @param {String} options.iv 可选
  18. */
  19. const mpWxGetSessionKey = async options=>{
  20. const {code, encryptedData, iv} = options;
  21. const {appId, secret} = wxConfigMp;
  22. let url = 'https://api.weixin.qq.com/sns/jscode2session';
  23. url += '?appid=' + appId;
  24. url += '&secret=' + secret;
  25. url += '&js_code=' + code + '&grant_type=authorization_code';
  26. const res = await uniCloud.httpclient.request(url, {
  27. method: 'GET',
  28. dataType: 'json'
  29. })
  30. const data = res.res.data;
  31. if(data.errcode){
  32. return {
  33. status: 0,
  34. msg: 'appid错误',
  35. data,
  36. appId
  37. }
  38. }
  39. if(!data.session_key){
  40. return {
  41. status: 0,
  42. msg: '获取微信授权失败',
  43. data
  44. }
  45. }
  46. if(!encryptedData || !iv){
  47. return {
  48. status: 1,
  49. openid: data.openid,
  50. session_key: data.session_key
  51. }
  52. }
  53. const userInfo = WXBizDataCrypt({
  54. sessionKey: data.session_key,
  55. encryptedData,
  56. iv
  57. })
  58. return {
  59. status: 1,
  60. session_key: data.session_key,
  61. ...userInfo
  62. }
  63. }
  64. /**
  65. * 获取AccessToken
  66. */
  67. const getAccessToken = async options=>{
  68. const accData = await db.collection('mix-access-token').get();
  69. let accInfo = {};
  70. if(accData.data.length === 1){
  71. accInfo = accData.data[0]
  72. //提前10分钟重新拉取
  73. if(accInfo.access_token && accInfo.expires_in*1000 > + new Date() - accInfo.add_time - 10*60*1000){
  74. return accInfo.access_token
  75. }
  76. }
  77. const {appId, secret} = wxConfigMp;
  78. let url = 'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential';
  79. url += '&appid=' + appId;
  80. url += '&secret=' + secret;
  81. const res = await uniCloud.httpclient.request(url, {
  82. method: 'GET',
  83. dataType: 'json'
  84. })
  85. await db.collection('mix-access-token').doc(accInfo._id || '1').set({
  86. access_token: res.data.access_token,
  87. expires_in: res.data.expires_in,
  88. add_time: + new Date()
  89. })
  90. return res.data.access_token;
  91. }
  92. /**
  93. * 解密encryptedData 获取unionid
  94. * @param {Object} options
  95. * @param {String} options.sessionKey
  96. * @param {String} options.encryptedData
  97. * @param {String} options.iv
  98. */
  99. const WXBizDataCrypt = options=>{
  100. const appId = wxConfigMp.appId;
  101. let {sessionKey, encryptedData, iv} = options;
  102. sessionKey = new Buffer(sessionKey, 'base64')
  103. encryptedData = new Buffer(encryptedData, 'base64')
  104. iv = new Buffer(iv, 'base64')
  105. let decoded;
  106. try {
  107. // 解密
  108. let decipher = crypto.createDecipheriv('aes-128-cbc', sessionKey, iv)
  109. // 设置自动 padding 为 true,删除填充补位
  110. decipher.setAutoPadding(true)
  111. decoded = decipher.update(encryptedData, 'binary', 'utf8')
  112. decoded += decipher.final('utf8')
  113. decoded = JSON.parse(decoded)
  114. } catch (err) {
  115. throw new Error('Illegal Buffer')
  116. }
  117. if (decoded.watermark.appid !== appId) {
  118. throw new Error('Illegal Buffer')
  119. }
  120. return decoded
  121. }
  122. module.exports = {
  123. mpWxGetSessionKey,
  124. WXBizDataCrypt,
  125. getAccessToken
  126. }