zoukankan      html  css  js  c++  java
  • 在项目中使用egg 的总结(持续更新文)

    使用 egg 实战微信小程序后端

    微信小程序授权登录流程

    官方图示

    我的理解

    .jpg

    node 的实现

    class AuthController extends BaseController {
      /**
       * 登录凭证校验
       * @param {number} appid 小程序appid 必传
       * @param {number} code 用户登录凭证(有效期五分钟)必传 
       * @param {string} encryptedData   包含unionId的微信用户信息 非必传
       * @param {string} iv 加密算法的初始向量 -必传
       * @param {number} timestamp 时间戳 非必传
       *
       */
      async code2session() {
        const { ctx } = this;
        const { appid, code } = ctx.request.body;
        const { secret } = this.mpInfo;
        const { service } = ctx;
        const { MicroAppUser } = ctx.modelMa;
        try {
          ctx.validate({
            appid: 'string',
            code: 'string'
          })
        } catch (err) {
          ctx.throw(400, err)
        }
        try {
          // 微信code2Session
          const wxC2sRes =  await this._wx_code2Session(appid, secret, code)
          // 生产sid
          const sid = await this._createSessionId()
    
          const unionid = wxC2sRes.unionid;
          const openid = wxC2sRes.openid;
          const wxUser = await this._getWxUserForDb(openid, appid) || '';
          const created = await MicroAppUser.findOrCreate({
            defaults: {
              sid,
              sessionKey: wxC2sRes.session_key,
              openid,
              unionid,
              uid
            },
            where: {
              appid,
              openid
            }
          }).spread((row, created) => { return created })
      
          if (!created) {
            // 更新sid
            await MicroAppUser.update({
              sid,
              sessionKey: wxC2sRes.session_key,
              openid,
              unionid,
              uid
            }, {
              where: {
                appid,
                openid
              }
            })
          }
    
          if (wxUser) wxUser.session_key = wxC2sRes.session_key;
          ctx.body = {
            code: 200, 
            data: {
              sid,
              openid: wxC2sRes.openid,
              ypUser,
              wxUser
            }
          }
        } catch (err) {
          ctx.throw(500, err)
        }
      }
      async code2sessionAndDecode () {
        const { ctx } = this;
        const { appid, code, encryptedData, iv,} = ctx.request.body;
        const { secret } = this.mpInfo;
        const { service, helper } = ctx;
        const { MicroAppUser } = ctx.modelMa;
        try {
          ctx.validate({
            appid: 'string',
            code: 'string'
          })
        } catch (err) {
          ctx.throw(400, err)
        }
        try {
          if (!iv) {
            return ctx.body = {
              code: 400,
              msg: `缺少必要参数vi`
            }
          }
    
          const wxC2sRes = await this._wx_code2Session(appid, secret, code)
    
          let sessionKey = wxC2sRes.session_key
          if (!sessionKey) {
            ctx.throw(500, 'sessionKey is not found')
          }
          // 生产sid
          const sid = await this._createSessionId()
    
          // 解码unionid获取微信用户信息
          const wxUser = await helper.encodeWxEncryptedData(appid, sessionKey, encryptedData, iv);
          const openid = wxUser.openId;
          const unionId = wxUser.unionId;
          const uid = unionId ? await service.rap.dubbox.getUserIdByUnionId(unionId) : 0;
          const ypUser = uid ? await service.rap.dubbox.getUserInfoById(uid) : '';
    
          if (ypUser) {
            ypUser.role = await this._getCrewRole(ypUser.uid)
          }
    
          const created = await MicroAppUser.findOrCreate({
            defaults: {
              sid,
              sessionKey,
              openid,
              unionid: unionId,
              uid
            },
            where: {
              appid,
              openid
            }
          }).spread((row, created) => { return created })
    
          if (!created) {
            // 更新sid
            await MicroAppUser.update({
              sid,
              sessionKey,
              openid,
              unionid: unionId,
              uid
            }, {
              where: {
                appid,
                openid
              }
            })
          }
    
          ctx.body = {
            code: 200, 
            data: {
              sid,
              ypUser,
              wxUser
            }
          }
        } catch (err) {
          ctx.throw(500, err)
        }
      }
      // 保存微信用户信息
      async saveUserInfo() {
        const { ctx, app } = this;
        const body = ctx.request.body;
        const { MicroAppUser } = app.modelMa;
      
        try {
          body.openid = ctx.openid || body.openId || body.openid
          body.nickname=body.nickname || body.nickName;
          const defaults = {
            appid: body.appid,
            openid: body.openid,
            unionid: body.unionid ||  body.unionId,
            sessionKey: body.session_key,
            nickname: body.nickname,
            gender: body.gender,
            avatarUrl: body.avatarUrl,
            country: body.country,
            province: body.province,
            city: body.city,
            language: body.language,
            uid: body.uid
          }
          this.logger.info(`saveUserInfo>>>${defaults}`)
      
          let result = await MicroAppUser.findOrCreate({
            raw: true,
            defaults,
            where: {
              openid: body.openid,
              appid: body.appid
            }
          })
          if (!result.created) {
            result = await MicroAppUser.update(defaults, {
              where: {
                openid: body.openid,
                appid: body.appid
              }
            })
          }
          return ctx.body = {
            code: 200,
            data: result,
            msg: '操作成功'
          }
        } catch (err) {
          ctx.throw(500, err)
        }
      }
      // 从DB获取微信用户信息
      async _getWxUserForDb(openid, appid) {
        return await this.app.mysql.get('microApp').select('micro_app_user', {
          where: {
            openid,
            appid
          }
        }).then(rows => {
          return rows = rows[0]
        })
      }
      // 创建sessionid
      async _createSessionId () {
        const { ctx } = this;
        const { appid, timestamp, uid, sid } = ctx.request.body;
        var str = ''
        if (appid) str += appid
        if (timestamp) str += timestamp
        if (sid) str += sid
        if (uid) str += uid
        return md5(str)
      }
      // 微信-登录凭证校验
      async _wx_code2Session(appid, secret, code) {
        try {
          const url = `https://api.weixin.qq.com/sns/jscode2session?appid=${appid}&secret=${secret}&js_code=${code}&grant_type=authorization_code`;
          const data = await this.ctx.curl(url, {
            method: 'get',
            contentType: 'json',
            timeout: 10000,
            dataType: 'json',
          })
          return data.data
        } catch (err) {
          this.ctx.throw(err)
        }
      }
    }
    
    

    利用 redis 优化注册接口

    redis 是实际上是利用内存在运行,所以为了防止用户注册两次时间间隔太短

    • 存入 redis
    • 从 redis 读取值存入数据库
    • 删除 redis 中的值
      async register() { 
        const { ctx, app, service } = this
        const { GlUser } = ctx.activityModel
        ctx.UID = await this.checkUid()
        // 插入到「我的」活动表
        let aid = this.actSetting.aid
        if (aid) {
          const result = await ctx.service.activity.activity.regActivity(
            ctx.UID,
            aid
          )
        }
        try {
          const userInfo = await ctx.service.activity.user.getUserInfoById(ctx.UID)
    
          // 如果头像来源是又拍云,则将头像缩放至 200*200 输出, 并改为 https 协议
          if (userInfo.avatar && userInfo.avatar.indexOf('upyun') > -1) {
            let index = userInfo.avatar.indexOf('://')
            userInfo.avatar = `https${userInfo.avatar.slice(
              index,
              userInfo.avatar.length
            )}!/sq/200`
          }
    
          const data = {
            uid: ctx.UID,
            nickname: userInfo.nickname,
            avatar: userInfo.avatar,
          }
    
          // redis是实际上是利用内存在运行,所以为了防止用户注册两次时间间隔太短
          // 1. 存入redis 2. 从redis读取值存入数据库 3. 删除redis中的值
          await service.redis.setRedis(this.redisKey + ctx.UID, data, this.settings.redisTime);
          const userData = await service.redis.getRedis(this.redisKey + ctx.UID);
    
          let result = await GlUser.findOrCreate({
            where: {
              uid: ctx.UID,
            },
            defaults: userData,
          }).spread((user, created) => { 
            return user
          })
    
          ctx.body = {
            code: 200,
            data: result,
            msg: 'success',
          }
    
          await service.redis.destroyRedis(this.redisKey + ctx.UID);
        } catch (error) {
          ctx.throw(500, error)
        }
      }
    

    参考:

    小程序登录

  • 相关阅读:
    io学习
    asp.net文件上传进度条研究
    asp.net页面中的Console.WriteLine结果如何查看
    谨慎跟随初始目的不被关联问题带偏
    android 按钮特效 波纹 Android button effects ripple
    安卓工作室 日志设置
    安卓工作室 文件浏览器 android studio File browser
    一个新的Android Studio 2.3.3可以在稳定的频道中使用。A new Android Studio 2.3.3 is available in the stable channel.
    新巴巴运动网上商城 项目 快速搭建 教程 The new babar sports online mall project quickly builds a tutorial
    码云,git使用 教程-便签
  • 原文地址:https://www.cnblogs.com/Jomsou/p/13334925.html
Copyright © 2011-2022 走看看