Open GMIS opened 6 years ago
我现在只能在小程序端不使用qcloud.loginWithCode()尝试避免这个错误,但没有找到“罪魁祸首”,也不知道是否靠谱。
怀疑是多个小程序使用wafer-node-sdk共用一个mysql服务器产生的问题,由于同一个用户在每个小程序中的openid都不一样,这样不同用户的openID可能相同,公用时可能会产生此类问题,这只是初步推测
// 查重并决定是插入还是更新数据
return mysql('cSessionInfo').count('open_id as hasUser').where({
open_id
})
.then(res => {
// 如果存在用户则更新
if (res[0].hasUser) {
return mysql('cSessionInfo').update({
skey, last_visit_time, session_key, user_info
}).where({
open_id
})
} else {
return mysql('cSessionInfo').insert({
uuid, skey, create_time, last_visit_time, open_id, session_key, user_info
})
}
})
应该是这里有问题了,如果A用户在小程序1的openID与B用户在小程序2的openID相同,那么在共用同一个数据库的情况下,B用户登陆检测到数据库已经存在此openID,那么就会用自己的userInfo更新,而A用户随后使用就会发现用自己openID返回了B的用户信息
在不修改数据库表的情况下,临时解决办法,为saveUserInfo添加一个appID参数:
function saveUserInfo (appID,userInfo, skey, session_key) {
const uuid = uuidGenerator()
const create_time = moment().format('YYYY-MM-DD HH:mm:ss')
const last_visit_time = create_time
const open_id = userInfo.openId+'-'+appID
const user_info = JSON.stringify(userInfo)
// 查重并决定是插入还是更新数据
return mysql('cSessionInfo').count('open_id as hasUser').where({
open_id
})
.then(res => {
// 如果存在用户则更新
if (res[0].hasUser) {
return mysql('cSessionInfo').update({
skey, last_visit_time, session_key, user_info
}).where({
open_id
})
} else {
return mysql('cSessionInfo').insert({
uuid, skey, create_time, last_visit_time, open_id, session_key, user_info
})
}
})
.then(() => ({
userinfo: userInfo,
skey: skey
}))
.catch(e => {
debug('%s: %O', ERRORS.DBERR.ERR_WHEN_INSERT_TO_DB, e)
throw new Error(`${ERRORS.DBERR.ERR_WHEN_INSERT_TO_DB}\n${e}`)
})
}
注意这句:const open_id = userInfo.openId+'-'+appID,由于添加了appID作为识别ID,这样就能确保不会产生openID冲突,当然更理想的情况下是更改数据库表中open_id为user_id,这样理解起来就不会与真正的openID产生混淆了
修改完后,再调用此函数的两个地方添加appID参数即可。
期望官方能针对此情况作出更好的设计。
忘了说了,getUserInfoByOpenId也要做相应修改:
function getUserInfoByOpenId (appID,openId) {
var userID = openId+'-'+appID
if (!openId) throw new Error(ERRORS.DBERR.ERR_NO_OPENID_ON_CALL_GETUSERINFOFUNCTION)
return mysql('cSessionInfo').select('*').where({ open_id: userID }).first()
}
这里的解决方案,是否是不同的小程序使用不同的 db 好点呢?
@jas0ncn 这个要看具体情况吧,不是所有小程序都是爆款,很可能多个小程序都没有什么流量,每一个都配独立数据库服务器太不经济,特别是对个人开发者来说,前景未明,在开发测试阶段,用一个数据库更划算。
如图所示,用正确的openID调用AuthDbService.getUserInfoByOpenId(openid),返回的结果确实另一个人的userInfo。
这里要出错,只可能是saveUserInfo出错,而调用此函数只有两个地方:一个是首次登陆时根据解密数据存储,第二个是二次登陆调用getUserInfoByOpenId()后更新skey。
从逻辑上说,前者解密不会出错,而后者是必定是前者出错后才会跟着出错,可出错的事实就在眼前,实在令人费解,希望能帮忙解决这个致命的问题。