tencentyun / wafer2-node-sdk

Wafer2 SDK for Node.js
Other
268 stars 59 forks source link

返回的用户信息出现奇怪的错误 #57

Open GMIS opened 5 years ago

GMIS commented 5 years ago

default 如图所示,用正确的openID调用AuthDbService.getUserInfoByOpenId(openid),返回的结果确实另一个人的userInfo。

这里要出错,只可能是saveUserInfo出错,而调用此函数只有两个地方:一个是首次登陆时根据解密数据存储,第二个是二次登陆调用getUserInfoByOpenId()后更新skey。

从逻辑上说,前者解密不会出错,而后者是必定是前者出错后才会跟着出错,可出错的事实就在眼前,实在令人费解,希望能帮忙解决这个致命的问题。

GMIS commented 5 years ago

我现在只能在小程序端不使用qcloud.loginWithCode()尝试避免这个错误,但没有找到“罪魁祸首”,也不知道是否靠谱。

GMIS commented 5 years ago

怀疑是多个小程序使用wafer-node-sdk共用一个mysql服务器产生的问题,由于同一个用户在每个小程序中的openid都不一样,这样不同用户的openID可能相同,公用时可能会产生此类问题,这只是初步推测

GMIS commented 5 years ago
// 查重并决定是插入还是更新数据
    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的用户信息

GMIS commented 5 years ago

在不修改数据库表的情况下,临时解决办法,为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参数即可。

期望官方能针对此情况作出更好的设计。

GMIS commented 5 years ago

忘了说了,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()
}
jas0ncn commented 5 years ago

这里的解决方案,是否是不同的小程序使用不同的 db 好点呢?

GMIS commented 5 years ago

@jas0ncn 这个要看具体情况吧,不是所有小程序都是爆款,很可能多个小程序都没有什么流量,每一个都配独立数据库服务器太不经济,特别是对个人开发者来说,前景未明,在开发测试阶段,用一个数据库更划算。