weixin.js 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. const crypto = require('crypto')
  2. const {
  3. userCollection
  4. } = require('../../common/constants')
  5. const {
  6. ERROR
  7. } = require('../../common/error')
  8. function decryptWeixinData ({
  9. encryptedData,
  10. sessionKey,
  11. iv
  12. } = {}) {
  13. const oauthConfig = this.configUtils.getOauthConfig({
  14. provider: 'weixin'
  15. })
  16. const decipher = crypto.createDecipheriv(
  17. 'aes-128-cbc',
  18. Buffer.from(sessionKey, 'base64'),
  19. Buffer.from(iv, 'base64')
  20. )
  21. // 设置自动 padding 为 true,删除填充补位
  22. decipher.setAutoPadding(true)
  23. let decoded
  24. decoded = decipher.update(encryptedData, 'base64', 'utf8')
  25. decoded += decipher.final('utf8')
  26. decoded = JSON.parse(decoded)
  27. if (decoded.watermark.appid !== oauthConfig.appid) {
  28. throw new Error('Invalid wechat appid in decode content')
  29. }
  30. return decoded
  31. }
  32. function getWeixinPlatform () {
  33. const platform = this.clientPlatform
  34. const userAgent = this.getClientInfo().userAgent
  35. switch (platform) {
  36. case 'app':
  37. case 'app-plus':
  38. return 'app'
  39. case 'mp-weixin':
  40. return 'mp'
  41. case 'h5':
  42. case 'web':
  43. return userAgent.indexOf('MicroMessenger') > -1 ? 'h5' : 'web'
  44. default:
  45. throw new Error('Unsupported weixin platform')
  46. }
  47. }
  48. async function saveWeixinUserKey ({
  49. openid,
  50. sessionKey, // 微信小程序用户sessionKey
  51. accessToken, // App端微信用户accessToken
  52. refreshToken, // App端微信用户refreshToken
  53. accessTokenExpired // App端微信用户accessToken过期时间
  54. } = {}) {
  55. // 微信公众平台、开放平台refreshToken有效期均为30天(微信没有在网络请求里面返回30天这个值,务必注意未来可能出现调整,需及时更新此处逻辑)。
  56. // 此前QQ开放平台有调整过accessToken的过期时间:[access_token有效期由90天缩短至30天](https://wiki.connect.qq.com/%E3%80%90qq%E4%BA%92%E8%81%94%E3%80%91access_token%E6%9C%89%E6%95%88%E6%9C%9F%E8%B0%83%E6%95%B4)
  57. const appId = this.getClientInfo().appId
  58. const weixinPlatform = getWeixinPlatform.call(this)
  59. const keyObj = {
  60. dcloudAppid: appId,
  61. openid,
  62. platform: 'weixin-' + weixinPlatform
  63. }
  64. switch (weixinPlatform) {
  65. case 'mp':
  66. await this.uniOpenBridge.setSessionKey(keyObj, {
  67. session_key: sessionKey
  68. }, 30 * 24 * 60 * 60)
  69. break
  70. case 'app':
  71. case 'h5':
  72. case 'web':
  73. await this.uniOpenBridge.setUserAccessToken(keyObj, {
  74. access_token: accessToken,
  75. refresh_token: refreshToken,
  76. access_token_expired: accessTokenExpired
  77. }, 30 * 24 * 60 * 60)
  78. break
  79. default:
  80. break
  81. }
  82. }
  83. function generateWeixinCache ({
  84. sessionKey, // 微信小程序用户sessionKey
  85. accessToken, // App端微信用户accessToken
  86. refreshToken, // App端微信用户refreshToken
  87. accessTokenExpired // App端微信用户accessToken过期时间
  88. } = {}) {
  89. const platform = getWeixinPlatform.call(this)
  90. let cache
  91. switch (platform) {
  92. case 'app':
  93. case 'h5':
  94. case 'web':
  95. cache = {
  96. access_token: accessToken,
  97. refresh_token: refreshToken,
  98. access_token_expired: accessTokenExpired
  99. }
  100. break
  101. case 'mp':
  102. cache = {
  103. session_key: sessionKey
  104. }
  105. break
  106. default:
  107. throw new Error('Unsupported weixin platform')
  108. }
  109. return {
  110. third_party: {
  111. [`${platform}_weixin`]: cache
  112. }
  113. }
  114. }
  115. function getWeixinOpenid ({
  116. userRecord
  117. } = {}) {
  118. const weixinPlatform = getWeixinPlatform.call(this)
  119. const appId = this.getClientInfo().appId
  120. const wxOpenidObj = userRecord.wx_openid
  121. if (!wxOpenidObj) {
  122. return
  123. }
  124. return wxOpenidObj[`${weixinPlatform}_${appId}`] || wxOpenidObj[weixinPlatform]
  125. }
  126. async function getWeixinCacheFallback ({
  127. userRecord,
  128. key
  129. } = {}) {
  130. const platform = getWeixinPlatform.call(this)
  131. const thirdParty = userRecord && userRecord.third_party
  132. if (!thirdParty) {
  133. return
  134. }
  135. const weixinCache = thirdParty[`${platform}_weixin`]
  136. return weixinCache && weixinCache[key]
  137. }
  138. async function getWeixinCache ({
  139. uid,
  140. userRecord,
  141. key
  142. } = {}) {
  143. const weixinPlatform = getWeixinPlatform.call(this)
  144. const appId = this.getClientInfo().appId
  145. if (!userRecord) {
  146. const getUserRes = await userCollection.doc(uid).get()
  147. userRecord = getUserRes.data[0]
  148. }
  149. if (!userRecord) {
  150. throw {
  151. errCode: ERROR.ACCOUNT_NOT_EXISTS
  152. }
  153. }
  154. const openid = getWeixinOpenid.call(this, {
  155. userRecord
  156. })
  157. const getCacheMethod = weixinPlatform === 'mp' ? 'getSessionKey' : 'getUserAccessToken'
  158. const userKey = await this.uniOpenBridge[getCacheMethod]({
  159. dcloudAppid: appId,
  160. platform: 'weixin-' + weixinPlatform,
  161. openid
  162. })
  163. if (userKey) {
  164. return userKey[key]
  165. }
  166. return getWeixinCacheFallback({
  167. userRecord,
  168. key
  169. })
  170. }
  171. module.exports = {
  172. decryptWeixinData,
  173. getWeixinPlatform,
  174. generateWeixinCache,
  175. getWeixinCache,
  176. saveWeixinUserKey
  177. }