From 4cbe46d6da75561e13fc926561f3a7a803ea80b3 Mon Sep 17 00:00:00 2001 From: wangyaqi Date: Tue, 25 Oct 2022 17:39:19 +0800 Subject: [PATCH] feat: secureNetworkHandshakeByWeixin --- .../uni-id-co/common/constants.js | 3 + .../cloudfunctions/uni-id-co/index.obj.js | 9 ++- .../uni-id-co/lib/utils/utils.js | 18 +++++ .../uni-id-co/lib/utils/weixin.js | 54 +++++++++++--- .../module/login/login-by-weixin-mobile.js | 5 +- .../uni-id-co/module/login/login-by-weixin.js | 19 ++++- .../uni-id-co/module/utils/index.js | 3 +- .../secure-network-handshake-by-weixin.js | 73 +++++++++++++++++++ .../cloudfunctions/uni-id-co/package.json | 6 +- 9 files changed, 171 insertions(+), 19 deletions(-) create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/utils.js create mode 100644 uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/utils/secure-network-handshake-by-weixin.js diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/common/constants.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/common/constants.js index 1a05d9a..f5888c4 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/common/constants.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/common/constants.js @@ -6,6 +6,8 @@ const verifyCollectionName = 'opendb-verify-codes' const verifyCollection = db.collection(verifyCollectionName) const deviceCollectionName = 'uni-id-device' const deviceCollection = db.collection(deviceCollectionName) +const openDataCollectionName = 'opendb-open-data' +const openDataCollection = db.collection(openDataCollectionName) const USER_IDENTIFIER = { username: 'username', @@ -78,6 +80,7 @@ module.exports = { userCollection, verifyCollection, deviceCollection, + openDataCollection, USER_IDENTIFIER, USER_STATUS, CAPTCHA_SCENE, diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/index.obj.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/index.obj.js index 24cbbc7..840fea8 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/index.obj.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/index.obj.js @@ -63,7 +63,8 @@ const { } = require('./module/verify/index') const { refreshToken, - setPushCid + setPushCid, + secureNetworkHandshakeByWeixin } = require('./module/utils/index') const { getInvitedUser, @@ -576,5 +577,9 @@ module.exports = { * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#unbind-apple * @returns */ - unbindApple + unbindApple, + /** + * 安全网络握手,目前仅处理微信小程序安全网络握手 + */ + secureNetworkHandshakeByWeixin } diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/utils.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/utils.js new file mode 100644 index 0000000..7d3e0f3 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/utils.js @@ -0,0 +1,18 @@ +let redisEnable = null +function getRedisEnable() { + // 未用到的时候不调用redis接口,节省一些连接数 + if (redisEnable !== null) { + return redisEnable + } + try { + uniCloud.redis() + redisEnable = true + } catch (error) { + redisEnable = false + } + return redisEnable +} + +module.exports = { + getRedisEnable +} \ No newline at end of file diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/weixin.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/weixin.js index 2a0f609..a01435d 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/weixin.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/lib/utils/weixin.js @@ -5,8 +5,14 @@ const { const { ERROR } = require('../../common/error') +const { + getRedisEnable +} = require('./utils') +const { + openDataCollection +} = require('../../common/constants') -function decryptWeixinData ({ +function decryptWeixinData({ encryptedData, sessionKey, iv @@ -31,7 +37,7 @@ function decryptWeixinData ({ return decoded } -function getWeixinPlatform () { +function getWeixinPlatform() { const platform = this.clientPlatform const userAgent = this.getClientInfo().userAgent switch (platform) { @@ -48,7 +54,7 @@ function getWeixinPlatform () { } } -async function saveWeixinUserKey ({ +async function saveWeixinUserKey({ openid, sessionKey, // 微信小程序用户sessionKey accessToken, // App端微信用户accessToken @@ -85,7 +91,36 @@ async function saveWeixinUserKey ({ } } -function generateWeixinCache ({ +async function saveSecureNetworkCache({ + code, + openid, + unionid, + sessionKey +}) { + const { + appId + } = this.getClientInfo() + const key = `uni-id:${appId}:weixin-mp:code:${code}:secure-network-cache` + const value = JSON.stringify({ + openid, + unionid, + session_key: sessionKey + }) + // 此处存储的是code的缓存,有效期两天即可 + const expiredSeconds = 2 * 24 * 60 * 60 + + await openDataCollection.doc(key).set({ + value, + expired: Date.now() + expiredSeconds * 1000 + }) + const isRedisEnable = getRedisEnable() + if (isRedisEnable) { + const redis = uniCloud.redis() + await redis.set(key, value, 'EX', expiredSeconds) + } +} + +function generateWeixinCache({ sessionKey, // 微信小程序用户sessionKey accessToken, // App端微信用户accessToken refreshToken, // App端微信用户refreshToken @@ -118,7 +153,7 @@ function generateWeixinCache ({ } } -function getWeixinOpenid ({ +function getWeixinOpenid({ userRecord } = {}) { const weixinPlatform = getWeixinPlatform.call(this) @@ -130,7 +165,7 @@ function getWeixinOpenid ({ return wxOpenidObj[`${weixinPlatform}_${appId}`] || wxOpenidObj[weixinPlatform] } -async function getWeixinCacheFallback ({ +async function getWeixinCacheFallback({ userRecord, key } = {}) { @@ -143,7 +178,7 @@ async function getWeixinCacheFallback ({ return weixinCache && weixinCache[key] } -async function getWeixinCache ({ +async function getWeixinCache({ uid, userRecord, key @@ -177,7 +212,7 @@ async function getWeixinCache ({ }) } -async function getWeixinAccessToken () { +async function getWeixinAccessToken() { const weixinPlatform = getWeixinPlatform.call(this) const appId = this.getClientInfo().appId @@ -194,5 +229,6 @@ module.exports = { generateWeixinCache, getWeixinCache, saveWeixinUserKey, - getWeixinAccessToken + getWeixinAccessToken, + saveSecureNetworkCache } diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-weixin-mobile.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-weixin-mobile.js index 2b21948..c27c2b2 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-weixin-mobile.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-weixin-mobile.js @@ -2,10 +2,7 @@ const { initWeixin } = require('../../lib/third-party/index') const { - getWeixinPlatform, - getWeixinAccessToken, - generateWeixinCache, - saveWeixinUserKey + getWeixinAccessToken } = require('../../lib/utils/weixin') const { ERROR diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-weixin.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-weixin.js index 84c7ddc..21d6071 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-weixin.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/login/login-by-weixin.js @@ -11,7 +11,8 @@ const { const { generateWeixinCache, getWeixinPlatform, - saveWeixinUserKey + saveWeixinUserKey, + saveSecureNetworkCache } = require('../../lib/utils/weixin') const { LOG_TYPE @@ -37,7 +38,9 @@ module.exports = async function (params = {}) { this.middleware.validate(params, schema) const { code, - inviteCode + inviteCode, + // 内部参数,暂不暴露 + secureNetworkCache = false } = params const { appId @@ -81,6 +84,18 @@ module.exports = async function (params = {}) { expired: accessTokenExpired // App端微信用户accessToken过期时间 } = getWeixinAccountResult + if (secureNetworkCache) { + if (weixinPlatform !== 'mp') { + throw new Error('Unsupported weixin platform, expect mp-weixin') + } + await saveSecureNetworkCache({ + code, + openid, + unionid, + sessionKey + }) + } + const { type, user diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/utils/index.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/utils/index.js index 11729f6..0ec67a5 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/utils/index.js +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/utils/index.js @@ -1,4 +1,5 @@ module.exports = { refreshToken: require('./refresh-token'), - setPushCid: require('./set-push-cid') + setPushCid: require('./set-push-cid'), + secureNetworkHandshakeByWeixin: require('./secure-network-handshake-by-weixin') } diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/utils/secure-network-handshake-by-weixin.js b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/utils/secure-network-handshake-by-weixin.js new file mode 100644 index 0000000..82ea0b3 --- /dev/null +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/module/utils/secure-network-handshake-by-weixin.js @@ -0,0 +1,73 @@ +const { + ERROR +} = require('../../common/error') +const { + initWeixin +} = require('../../lib/third-party/index') +const { + saveWeixinUserKey, + saveSecureNetworkCache +} = require('../../lib/utils/weixin') +const loginByWeixin = require('../login/login-by-weixin') +/** + * 微信安全网络握手 + * @tutorial https://uniapp.dcloud.net.cn/uniCloud/uni-id-pages.html#set-push-cid + * @param {object} params + * @param {string} params.code 微信登录返回的code + * @param {boolean} params.callLoginByWeixin 是否同时调用一次微信登录 + * @returns + */ +module.exports = async function (params = {}) { + const schema = { + code: 'string', + callLoginByWeixin: { + type: 'boolean', + required: false + } + } + this.middleware.validate(params, schema) + let platform = this.clientPlatform + if (platform !== 'mp-weixin') { + throw new Error(`[secureNetworkHandshake] platform ${platform} is not supported`) + } + const { + code, + callLoginByWeixin = false + } = params + if (callLoginByWeixin) { + return loginByWeixin.call(this, { + code, + secureNetworkCache: true + }) + } + + const weixinApi = initWeixin.call(this) + let getWeixinAccountResult + try { + getWeixinAccountResult = await weixinApi.code2Session(code) + } catch (error) { + console.error(error) + throw { + errCode: ERROR.GET_THIRD_PARTY_ACCOUNT_FAILED + } + } + const { + openid, + unionid, + sessionKey // 微信小程序用户sessionKey + } = getWeixinAccountResult + await saveSecureNetworkCache.call(this, { + code, + openid, + unionid, + sessionKey + }) + await saveWeixinUserKey.call(this, { + openid, + sessionKey + }) + + return { + errCode: 0 + } +} diff --git a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/package.json b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/package.json index 2277a0d..47f1d57 100644 --- a/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/package.json +++ b/uni_modules/uni-id-pages/uniCloud/cloudfunctions/uni-id-co/package.json @@ -14,6 +14,10 @@ "uni-open-bridge-common": "file:../../../../uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common" }, "extensions": { - "uni-cloud-sms": {} + "uni-cloud-sms": {}, + "uni-cloud-redis": {} + }, + "cloudfunction-config": { + "keepRunningAfterReturn": false } } -- GitLab