记微信网页授权登录-node

1,582 阅读2分钟

准备工作

开发者ID和开发者密码

登录微信公众平台->开发->获取开发者ID(AppID)和开发者密码(AppSecret)。

网页授权

登录微信公众平台->开发->网页授权(修改)->网页授权域名(设置)->按提示下载文件上传服务器设置域名通过验证即可。

unionid

微信开放平台绑定公众号,获取用户信息时才会有unionid;
openid:需要该用户关注了公众号才产生,公众号下唯一,包括其他微信接口都需要此值;
unionid:微信开放平台下多个公众号,或在公众号、移动应用之间统一的用户帐号

开发者

登录微信公众平台->开发->开发者工具->web开发者工具->绑定开发者微信号->按提示

class Wechat {
  // !!!!utils不存在,只做示例;
  constructor(appid, appsecret, redirect_uri) {
    super()
    this.appid = appid
    this.appsecret = appsecret
    this.redirect_uri = encodeURIComponent(redirect_uri)
  }

  wechat(req, res) {
    let redirect_uri = this.redirect_uri
    if (req.query.referer) {
      // 回调地址以redirect_uri查询字符串传递,重定向时会进行decode。所以需要再次encode;
      redirect_uri += encodeURIComponent('?referer=' + encodeURIComponent(req.query.referer))
    } else {
      return '回调url,referer参数不存在'
    }

    let scope = req.query.scope || 'snsapi_userinfo'

    redirect_uri = 'https://open.weixin.qq.com/connect/oauth2/authorize?appid=' + this.appid + '&redirect_uri=' + redirect_uri + '&response_type=code&scope=' + scope + '#wechat_redirect'
    this.redirect(res, redirect_uri)
    return null
  }

  async getAccessToken(req, res) {
    let referer = req.query.referer
    let code = req.query.code
    let errcode = null
    let userinfo = null
    let token = ''

    if (code && referer) {
      // 使用 code 请求获取 access_token、appid
      let data = utils.require('https://api.weixin.qq.com/sns/oauth2/access_token?appid=' + this.appid + '&secret=' + this.appsecret + '&code=' + code + '&grant_type=authorization_code')

      if (data.errcode) {
        errcode = 100002
      } else {

        if (data.scope === 'snsapi_userinfo') {
        // 使用 access_token、appid 获取用户信息
          userinfo = await utils.request('https://api.weixin.qq.com/sns/userinfo?access_token=' + data.access_token + '&openid=' + data.openid + '&lang=zh_CN')

          if (userinfo.errcode) {
            errcode = userinfo.errcode
          } else {
            //nickname的Emoji表情符号处理
            userInfo.nickname = encodeURIComponent(userInfo.nickname)
            // 用户存表
            let insertUserinfo = await utils.insertUser('urer', userinfo)

            if (insertUserinfo.insertId) {
              // 写redis
              let token = utils.md5(userinfo.openid)
              let setRedisResult = await this.setUserinfoToRedis(token, userinfo)

              if (setRedisResult) {
                errcode = setRedisResult
              }
            } else {
              errcode = 103306
            }
          }
        } else {
          // 处理 scope = snsapi_base,客户端可以存某个值来判断用户是否第一次微信登录
          // 如果不是第一次登录,可以用openid查用户表
          userinfo = utils.queryUser('urer', { 'openId': '= ' + data.openid })
          let token = utils.md5(userinfo.openid)

          if (userinfo) {
            let setRedisResult = await this.setUserinfoToRedis(token, userinfo)

            if (setRedisResult) {
              errcode = setRedisResult
            }
          } else {
            errcode = 113306
          }
        }
      }
    } else {
      errcode = -5
    }

    if (errcode) {
      this.redirect(res, referer, 'errcode=' + errcode)
    } else {
      this.redirect(res, referer, 'token=' + token)
    }

    return null
  }

  async getUserinfo(req) {
    let token = req.query.token

    if (token) {
      let userinfo = await utils.getUserinfoByRedis(token)

      if (userinfo) {
        await utils.delRedis(token)
        return JSON.parse(userinfo.toString())
      } else {
        return { errcode: 100001 }
      }
    } else {
      return '参数,token不存在'
    }
  }

  async setUserinfoToRedis(token, userinfo) {
    if (userinfo) {
      // 写Redis,用来获取用户,2分钟后过期,获取一次后删除;
      let setUserinfo = await utils.setRedis(token, JSON.stringify(userinfo))
      let expireUserinfo = await utils.expireRedis(token, 2 * 60)
      if (!(setUserinfo && expireUserinfo)) {
        return 106379
      } else {
        return null
      }
    } else {
      return 116379
    }
  }

  redirect(res, redirect_uri, queryStr) {
    if (queryStr) {
      if (redirect_uri.indexOf('?') === -1) {
        redirect_uri += '?'
      }
      if (referer.indexOf('&') !== -1) {
        redirect_uri += '&'
      }
      redirect_uri += queryStr
    }

    res.writeHead(302, {
      Location: redirect_uri
    })
    res.end()
  }

}