近期业务用到微信登陆并同步 mongo 数据库,但目前微信官方只给了wafer2-quickstart-nodejs这个 koa2+mysql 方案,google+git 也并没有找到轮子或方案,就自己写了个轮子(附小程序 demo ) 地址:https://github.com/seawind8888/weapp-node-mongo-scaffold
微信官方文档只给了微信登录流程图,但并没有给出同步数据库登录的流程。并且各种 openId、sessionKey、iv 等相关的鉴权字段也是搞得人很懵逼,按照自己轮流程做了个图,供参考
先启动项目
使用微信开发者工具导入项目目录下 example 项目,并填入自己申请的AppID
进入项目,关闭详情 - 不校验合法域名
点击微信同步登陆,提示用户入库成功,并返回 session_key 和 token (可存入 storage 并加入请求 header )
mongo 入库用户信息成功
Tips: 客户端调用 wx.login 生成 token,实际有两个鉴权逻辑(微信鉴权,客户端交互 token 鉴权),客户端可先使用 wx.checkSession 判断微信鉴权,再获取客户端鉴权
loginAction = async (ctx) => {
// 调用 /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 => {
// 设置 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: '参数错误',
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: '服务器内部错误',
data: error
}
};
}
}
});
}