V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
seawind8888
V2EX  ›  程序员

node 实现小程序用户登录 mongo 同步(附轮子)

  •  
  •   seawind8888 ·
    seawind8888 · 2019-07-22 11:31:14 +08:00 · 1065 次点击
    这是一个创建于 1712 天前的主题,其中的信息可能已经有所发展或是发生改变。

    近期业务用到微信登陆并同步 mongo 数据库,但目前微信官方只给了wafer2-quickstart-nodejs这个 koa2+mysql 方案,google+git 也并没有找到轮子或方案,就自己写了个轮子(附小程序 demo ) 地址:https://github.com/seawind8888/weapp-node-mongo-scaffold

    同步流程

    微信官方文档只给了微信登录流程图,但并没有给出同步数据库登录的流程。并且各种 openId、sessionKey、iv 等相关的鉴权字段也是搞得人很懵逼,按照自己轮流程做了个图,供参考 image

    效果实现

    先启动项目

    1. 使用微信开发者工具导入项目目录下 example 项目,并填入自己申请的AppID

    2. 进入项目,关闭详情 - 不校验合法域名 image

    3. 点击微信同步登陆,提示用户入库成功,并返回 session_key 和 token (可存入 storage 并加入请求 header ) image

    4. mongo 入库用户信息成功 image

    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
                  }
                };
              }
            }
          });
      }
    
    目前尚无回复
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   3552 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 29ms · UTC 04:48 · PVG 12:48 · LAX 21:48 · JFK 00:48
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.