近期業(yè)務(wù)用到微信登陸并同步mongo數(shù)據(jù)庫,但目前微信官方只給了wafer2-quickstart-nodejs這個koa2+mysql方案,google+git也并沒有找到輪子或方案,就自己寫了個輪子(附小程序demo)
地址:https://github.com/seawind8888/weapp-node-mongo-scaffold
同步流程
微信官方文檔只給了微信登錄流程圖,但并沒有給出同步數(shù)據(jù)庫登錄的流程。并且各種openId、sessionKey、iv等相關(guān)的鑒權(quán)字段也是搞得人很懵逼,按照自己輪流程做了個圖,供參考

image
效果實現(xiàn)
先啟動項目
使用微信開發(fā)者工具導(dǎo)入項目目錄下example項目,并填入自己申請的AppID
-
進(jìn)入項目,關(guān)閉詳情 - 不校驗合法域名
image -
點(diǎn)擊微信同步登陸,提示用戶入庫成功,并返回session_key和token(可存入storage并加入請求header)
image -
mongo入庫用戶信息成功
image
Tips: 客戶端調(diào)用wx.login生成token,實際有兩個鑒權(quán)邏輯(微信鑒權(quán),客戶端交互token鑒權(quán)),客戶端可先使用wx.checkSession判斷微信鑒權(quán),再獲取客戶端鑒權(quán)
同步實現(xiàn)邏輯
loginAction = async (ctx) => {
// 調(diào)用/user/login
const {
encryptedData,
code,
iv
} = ctx.query
const {
AppID,
AppSecret
} = config.weapp
// 開始獲取openId && session_key
const resultData = await this.getAppId({
appid: AppID,
secret: AppSecret,
code: code
});
// 解密微信簽名,獲取用戶信息
const decode = new WXBizDataCrypt(AppID, resultData.session_key)
const userInfo = decode.decryptData(encryptedData, iv)
// 引入小程序用戶的model
const WeChatUser = mongoose.model('User');
// 查詢用戶信息
await WeChatUser.findOne({
openid: resultData.openid
})
.exec()
.then(async result => {
// 設(shè)置token格式
const userToken = {
openid: resultData.openid
}
if (!result) {
// 首次登錄生成token, 有效期為24小時?
const token = jwt.sign(userToken, secret, {
expiresIn: 60 * 60 * 24
})
const NewWechatUser = new WeChatUser({
// 用戶信息入庫
avatar: userInfo.avatarUrl,
nickName: userInfo.nickName,
openid: resultData.openid,
token: token
});
try {
const _save = await NewWechatUser.save()
console.log('[mongoSave]', _save)
//成功返回code=200,并返回成sessionKey
ctx.body = {
statusCode: 200,
message: '登錄成功, 用戶信息入庫成功',
Token: token,
sessionKey: resultData.session_key
};
} catch (error) { //失敗返回code=500,并返回錯誤信息
console.log('[tokenSave]', error)
ctx.body = {
statusCode: 500,
message: '參數(shù)錯誤',
data: error
}
}
} else { // 已添加token
const token = result.token
try {
// token校驗
await jwt.verify(token, secret)
ctx.body = {
statusCode: 200,
message: '登錄成功,用戶已入庫',
Token: token,
sessionKey: resultData.session_key
};
} catch (err) {
if (err && err.name == 'TokenExpiredError') {
// token失效
const token = jwt.sign(userToken, secret, {
expiresIn: 60 * 60 * 24
})
// 更新token
const _update = WeChatUser.updateOne(secret, token)
console.log('[mongoUpdate]', _update)
ctx.body = {
statusCode: 200,
message: '登錄成功,Token更新成功',
Token: token,
sessionKey: resultData.session_key
};
} else {
console.log('[tokenVerify]', error)
ctx.body = {
statusCode: 500,
message: '服務(wù)器內(nèi)部錯誤',
data: error
}
};
}
}
});
}


