Skip to content

Commit

Permalink
Merge branch 'master' into sms-message
Browse files Browse the repository at this point in the history
  • Loading branch information
zhangzeshuan committed Sep 10, 2019
2 parents 64b5cb8 + 3a0336a commit 3db1bf0
Show file tree
Hide file tree
Showing 12 changed files with 475 additions and 3 deletions.
4 changes: 4 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ module.exports = {
describe: true,
it: true,
my: true,
qq: true,
swan: true,
expect: true,
beforeEach: true,
before: true,
Expand All @@ -26,5 +28,7 @@ module.exports = {
__VERSION_WEB__: true,
__VERSION_ALIPAY__: true,
__VERSION_WECHAT__: true,
__VERSION_QQ__: true,
__VERSION_BAIDU__: true,
}
}
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
## 2.5.0 (2019-9-3)
- [A] 支持百度小程序

## 2.4.0 (2019-8-21)
- [A] QQ SDK 支持 QQ 小程序支付
- [A] web 端支持 QQ 扫码支付
Expand Down
13 changes: 13 additions & 0 deletions core/UserRecord.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,19 @@ class UserRecord extends BaseRecord {
return BaaS._polyfill.linkQQ.apply(null, arguments)
}

/**
* 将当前用户关联至百度账号
*/
linkBaidu() {
if (this._anonymous) {
return Promise.reject(new HError(612))
}
if (!BaaS._polyfill.linkBaidu) {
return Promise.reject(new HError(605, 'linkBaidu 方法未定义'))
}
return BaaS._polyfill.linkBaidu.apply(null, arguments)
}

linkThirdParty() {
if (this._anonymous) {
return Promise.reject(new HError(612))
Expand Down
6 changes: 6 additions & 0 deletions core/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,12 @@ const API = {
DECRYPT: '/hserve/v2.0/qq/decrypt/',
},

BAIDU: {
SILENT_LOGIN: '/hserve/v2.1/idp/baidu/silent-login/',
AUTHENTICATE: '/hserve/v2.1/idp/baidu/authenticate/',
USER_ASSOCIATE: '/hserve/v2.1/idp/baidu/user-association/',
},

ALIPAY: {
SILENT_LOGIN: '/hserve/v2.1/idp/alipay/silent-login/',
AUTHENTICATE: '/hserve/v2.1/idp/alipay/authenticate/',
Expand Down
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "minapp-sdk",
"version": "2.4.0",
"version": "2.5.0",
"main": "./lib/index.js",
"browser": "./lib/web.js",
"miniprogram": "lib",
Expand Down Expand Up @@ -34,8 +34,8 @@
},
"homepage": "https://github.com/ifanrx/repository#readme",
"versions": {
"alipay": "2.4.0",
"web": "2.4.0"
"alipay": "2.5.0",
"web": "2.5.0"
},
"devDependencies": {
"@babel/core": "^7.2.2",
Expand Down
160 changes: 160 additions & 0 deletions sdk-file/src/baidu/auth.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
const constants = require('core-module/constants')
const HError = require('core-module/HError')
const storage = require('core-module/storage')
const utils = require('core-module/utils')
const commonAuth = require('core-module/auth')

module.exports = BaaS => {
const API = BaaS._config.API

const getLoginCode = () => {
return new Promise((resolve, reject) => {
swan.login({
success: res => {
resolve(res.code)
},
fail: (err) => {
BaaS.request.swanRequestFail(reject)
},
})
})
}

// 获取登录凭证 code, 进而换取用户登录态信息
const auth = ({createUser = true} = {}) => {
return new Promise((resolve, reject) => {
getLoginCode().then(code => {
sessionInit({code, createUser}, resolve, reject)
}, reject)
})
}

// code 换取 session_key,生成并获取 3rd_session 即 token
const sessionInit = ({code, createUser}, resolve, reject) => {
return BaaS.request({
url: API.BAIDU.SILENT_LOGIN,
method: 'POST',
data: {
create_user: createUser,
code: code
}
}).then(utils.validateStatusCode).then(res => {
BaaS._polyfill.handleLoginSuccess(res)
resolve(res)
}, reject)
}

const silentLogin = utils.rateLimit(function (...args) {
if (storage.get(constants.STORAGE_KEY.AUTH_TOKEN) && !utils.isSessionExpired()) {
return Promise.resolve()
}
return auth(...args)
})

const getSensitiveData = (data) => {
return BaaS.request({
url: API.BAIDU.AUTHENTICATE,
method: 'POST',
data,
}).then(utils.validateStatusCode)
}

const getUserInfo = ({lang} = {}) => {
return new Promise((resolve, reject) => {
swan.getUserInfo({
lang,
success: resolve, fail: reject
})
})
}

// 提供给开发者在 button (open-type="getUserInfo") 的回调中调用,对加密数据进行解密,同时将 userinfo 存入 storage 中
const handleUserInfo = res => {
if (!res || !res.detail) {
throw new HError(603)
}

let detail = res.detail
let createUser = !!res.createUser
let syncUserProfile = res.syncUserProfile

// 用户拒绝授权,仅返回 uid, openid
if (!detail.userInfo) {
return Promise.reject(Object.assign(new HError(603), {
id: storage.get(constants.STORAGE_KEY.UID),
openid: storage.get(constants.STORAGE_KEY.OPENID),
}))
}

return getLoginCode().then(code => {
return getUserInfo({lang: detail.userInfo.language}).then(detail => {
let payload = {
code,
create_user: createUser,
data: detail.data,
iv: detail.iv,
update_userprofile: utils.getUpdateUserProfileParam(syncUserProfile),
}
return getSensitiveData(payload)
})
}).then(res => {
BaaS._polyfill.handleLoginSuccess(res)
})
}


const linkBaidu = (res, {
syncUserProfile = constants.UPDATE_USERPROFILE_VALUE.SETNX,
} = {}) => {
let refreshUserInfo = false
if (res && res.detail && res.detail.userInfo) {
refreshUserInfo = true
}

return getLoginCode().then(code => {
// 如果用户传递了授权信息,则重新获取一次 userInfo, 避免因为重新获取 code 导致 session 失效而解密失败
let getUserInfoPromise = refreshUserInfo
? getUserInfo({lang: res.detail.userInfo.language})
: Promise.resolve(null)

return getUserInfoPromise.then(res => {
let payload = res ? {
rawData: res.rawData,
signature: res.signature,
encryptedData: res.encryptedData,
iv: res.iv,
update_userprofile: utils.getUpdateUserProfileParam(syncUserProfile),
code
} : {code}

return BaaS._baasRequest({
method: 'POST',
url: API.BAIDU.USER_ASSOCIATE,
data: payload,
})
})
})
}

const loginWithBaidu = (authData, {
createUser = true,
syncUserProfile = constants.UPDATE_USERPROFILE_VALUE.SETNX,
} = {}) => {
let loginPromise = null
if (authData && authData.detail) {
// handleUserInfo 流程
loginPromise = handleUserInfo(Object.assign(authData, {createUser, syncUserProfile}))
} else {
// 静默登录流程
loginPromise = silentLogin({createUser})
}

return loginPromise.then(() => commonAuth.getCurrentUser())
}

Object.assign(BaaS.auth, {
silentLogin,
loginWithBaidu: utils.rateLimit(loginWithBaidu),
linkBaidu: utils.rateLimit(linkBaidu),
})
}
40 changes: 40 additions & 0 deletions sdk-file/src/baidu/baasRequest.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
const utils = require('core-module/utils')
const BaaS = require('core-module/baas')
const constants = require('core-module/constants')
const storage = require('core-module/storage')

/**
*
* @param {object} payload
*/
function tryResendRequest(payload) {
// 情景1:若是第一次出现 401 错误,此时的缓存一定是过期的。
// 情景2:假设有 a,b 两个 401 错误的请求,a请求 300ms 后返回,走情景 1 的逻辑。b 在 pending 10 秒后返回,此时缓存实际上是没过期的,但是仍然会重新清空缓存,走情景 1 逻辑。
// 情景3:假设有 a,b,c 3 个并发请求,a 先返回,走了情景 1 的逻辑,此时 bc 请求在 silentLogin 请求返回前返回了,这时候他们会等待 silentLogin , 即多个请求只会发送一次 silentLogin 请求
if (storage.get(constants.STORAGE_KEY.AUTH_TOKEN)) {
// 缓存被清空,silentLogin 一定会发起 session init 请求
BaaS.clearSession()
}

BaaS.auth.silentLogin().then(() => {
return BaaS.request(payload).then(utils.validateStatusCode)
})
}

// BaaS 网络请求,此方法能保证在已登录 BaaS 后再发起请求
// eslint-disable-next-line no-unused-vars
const baasRequest = function ({url, method = 'GET', data = {}, header = {}, dataType = 'json'}) {
let beforeRequestPromise = BaaS._config.AUTO_LOGIN ? BaaS.auth.silentLogin() : Promise.resolve()

return beforeRequestPromise.then(() => {
return BaaS.request.apply(null, arguments)
}).then(res => {
if (res.statusCode === constants.STATUS_CODE.UNAUTHORIZED && BaaS._config.AUTO_LOGIN) {
return tryResendRequest({header, method, url, data, dataType})
} else {
return utils.validateStatusCode(res)
}
})
}

module.exports = baasRequest
20 changes: 20 additions & 0 deletions sdk-file/src/baidu/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
const BaaS = require('core-module/baas')
const core = require('core-module/index')
const polyfill = require('./polyfill')
const auth = require('./auth')

BaaS._config.VERSION = __VERSION_BAIDU__

BaaS.use(core)
BaaS.use(polyfill)
BaaS.use(auth)
BaaS.request = require('./request')
BaaS._baasRequest = require('./baasRequest')
BaaS.uploadFile = require('./uploadFile')
BaaS._createRequestMethod()
// 暴露 BaaS 到小程序环境
if (typeof swan !== 'undefined') {
swan.BaaS = BaaS
}

module.exports = BaaS
44 changes: 44 additions & 0 deletions sdk-file/src/baidu/polyfill.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
const constants = require('core-module/constants')
module.exports = BaaS => {
Object.assign(BaaS._polyfill, {
CLIENT_PLATFORM: 'BAIDU',
setStorageSync(k, v) {
return swan.setStorageSync(k, v)
},
getStorageSync(k) {
return swan.getStorageSync(k)
},
getSystemInfoSync() {
return swan.getSystemInfoSync()
},
checkLatestVersion() {
let info = swan.getSystemInfoSync()
if (info.platform === 'devtools') {
BaaS.checkVersion({platform: 'baidu_miniapp'})
}
},
linkBaidu(...args) {
return BaaS.auth.linkBaidu(...args)
},
handleLoginSuccess(res, isAnonymous) {
// 登录成功的 hook (login、loginWithWechat、register)调用成功后触发
BaaS.storage.set(constants.STORAGE_KEY.UID, res.data.user_id)
BaaS.storage.set(constants.STORAGE_KEY.OPENID, res.data.openid || '')
BaaS.storage.set(constants.STORAGE_KEY.AUTH_TOKEN, res.data.token)
BaaS.storage.set(constants.STORAGE_KEY.UNIONID, res.data.unionid || '')
if (res.data.openid) {
BaaS.storage.set(constants.STORAGE_KEY.USERINFO, {
id: res.data.user_id,
openid: res.data.openid,
unionid: res.data.unionid,
})
}
BaaS.storage.set(constants.STORAGE_KEY.EXPIRES_AT, Math.floor(Date.now() / 1000) + res.data.expires_in - 30)
if (isAnonymous) {
BaaS.storage.set(constants.STORAGE_KEY.IS_ANONYMOUS_USER, 1)
} else {
BaaS.storage.set(constants.STORAGE_KEY.IS_ANONYMOUS_USER, 0)
}
},
})
}
49 changes: 49 additions & 0 deletions sdk-file/src/baidu/request.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
const BaaS = require('core-module/baas')
const HError = require('core-module/HError')
const utils = require('core-module/utils')
const constants = require('core-module/constants')

const swanRequestFail = function (reject) {
swan.getNetworkType({
success: function (res) {
if (res.networkType === 'none') {
reject(new HError(600)) // 断网
} else {
reject(new HError(601)) // 网络超时
}
}
})
}

const request = ({url, method = 'GET', data = {}, header = {}, dataType = 'json'}) => {
return new Promise((resolve, reject) => {

if (!BaaS._config.CLIENT_ID) {
return reject(new HError(602))
}

let headers = utils.mergeRequestHeader(header)

if (!/https?:\/\//.test(url)) {
const API_HOST = BaaS._config.DEBUG ? BaaS._config.API_HOST : BaaS._polyfill.getAPIHost()
url = API_HOST.replace(/\/$/, '') + '/' + url.replace(/^\//, '')
}

swan.request({
method: method,
url: url,
data: data,
header: headers,
dataType: dataType,
success: resolve,
fail: (err) => {
swanRequestFail(reject)
}
})

utils.log(constants.LOG_LEVEL.INFO, 'Request => ' + url)
})
}

module.exports = request
module.exports.swanRequestFail = swanRequestFail
Loading

0 comments on commit 3db1bf0

Please sign in to comment.