koa2实现微信小程序用户登录mongo同步(附轮子)
近期业务用到微信登陆并同步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
}
};
}
}
});
}