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)
        }
      }
    

    参考:

    小程序登录

  • 相关阅读:
    OCP-1Z0-053-V12.02-597题
    OCP-1Z0-053-V12.02-599题
    OCP-1Z0-053-V12.02-609题
    OCP-1Z0-053-V12.02-604题
    OCP-1Z0-053-V12.02-607题
    OCP-1Z0-053-V12.02-588题
    OCP-1Z0-053-V12.02-592题
    OCP-1Z0-053-V12.02-587题
    OCP-1Z0-053-V12.02-582题
    OCP-1Z0-053-V12.02-583题
  • 原文地址:https://www.cnblogs.com/Jomsou/p/13334925.html
Copyright © 2011-2022 走看看