微信小程序登陆流程(20200322)

客户端

开发版和测试版首次登录需要用户手动触发登录。比如点击指定登录组件

 <button open-type="getUserInfo" bindgetuserinfo="bindGetUserInfo">新版登录</button>

对应的事件处理

Page({
  bindGetUserInfo: function (e) {
    console.log(e.detail.userInfo)
    if (e.detail.userInfo) {
      // 用户按了接受按钮
      app.doLogin(this.getUserInfo);
    } else {
      //用户按了拒绝按钮
    }
  },
  getUserInfo: function () {
    let that = this;
    let userInfo = app.globalData.userInfo;
    console.info('userInfo is:', userInfo);

    if (userInfo) {
      that.setData({
        hasLogin: true,
        userInfo: userInfo
      });
      wx.hideLoading();
    } else {
      console.log('globalData中userInfo为空');
    }
  },
  // 登录动作
  doLogin: function (callback = () => { }) {
    let that = this;
    wx.login({
      success: function (loginRes) {
        log('wx.login执行成功', loginRes);
        if (loginRes.code) {
          /* 
           * @desc: 获取用户信息 期望数据如下 
           *
           * @param: userInfo       [Object]
           * @param: rawData        [String]
           * @param: signature      [String]
           * @param: encryptedData  [String]
           * @param: iv             [String]
           **/
          wx.getUserInfo({

            withCredentials: true, // 非必填, 默认为true

            success: function (infoRes) {
              console.log('wx.getUserInfo成功', infoRes)
              // 请求服务端的登录接口
              wx.request({
                url: api.loginUrl,

                data: {
                  code: loginRes.code, // 临时登录凭证
                  rawData: infoRes.rawData, // 用户非敏感信息
                  signature: infoRes.signature, // 签名
                  encryptedData: infoRes.encryptedData, // 用户敏感信息
                  iv: infoRes.iv // 解密算法的向量
                },

                success: function (res) {
                  console.log('login success');
                  res = res.data;

                  if (res.result == 0) {
                    that.globalData.userInfo = res.userInfo;
                    wx.setStorageSync('userInfo', JSON.stringify(res.userInfo));
                    wx.setStorageSync('loginFlag', res.skey);
                    callback();
                  } else {
                    that.showInfo(res.errmsg);
                  }
                },

                fail: function (error) {
                  // 调用服务端登录接口失败
                  log('调用服务端登录接口失败', error);
                  that.showInfo('调用接口失败');
                  console.log(error);
                }
              });
            },

            fail: function (error) {
              // 获取 userInfo 失败,去检查是否未开启权限
              log('获取 userInfo 失败');
              wx.hideLoading();
              that.checkUserInfoPermission();
            }
          });

        } else {
          // 获取 code 失败
          that.showInfo('登录失败');
          console.log('调用wx.login获取code失败');
        }
      },

      fail: function (error) {
        // 调用 wx.login 接口失败
        that.showInfo('接口调用失败');
        console.log(error);
      }
    });
  },
})

服务端

根据客户端传过来的临时登录凭证,以及小程序注册时获取的appidappSecret,可以从微信服务器中拿到登录态标识session_key,进而拿到这个用户的唯一标识openId和其它非敏感信息。
这个唯一标识openId也可以作为你的业务系统中用户的唯一标识。

const http = require('axios');
const crypto = require('crypto');
const { appConfig: config } = require('../conf/app');
const { decryptByAES, encryptSha1 } = require('../util/util');
const { saveUserInfo } = require('../controllers/users');
/**
 * 登录校验中间件
 */
function authorizeMiddleware(req, res, next) {
  return authMiddleware(req).then(function (result) {

    // 将结果存入响应信息的'auth_data'字段
    res['auth_data'] = result;
    return next();

  })
}

function authMiddleware(req) {
  const {
    appid,
    secret
  } = config;

  const {
    code,
    encryptedData,
    iv
  } = req.query;

  // 检查参数完整性
  if ([code, encryptedData, iv].some(item => !item)) {
    return {
      result: -1,
      errmsg: '缺少参数字段,请检查后重试'
    }
  }

  // 获取 session_key和 openid
  return getSessionKey(code, appid, secret)
    .then(resData => {
      // 选择加密算法生成自己的登录态标识
      const { session_key } = resData;
      const skey = encryptSha1(session_key);

      let decryptedData = JSON.parse(decryptByAES(encryptedData, session_key, iv));
      console.log('-------------decryptedData---------------');
      console.log(decryptedData);
      console.log('-------------decryptedData---------------');

      // 存入用户数据表中
      return saveUserInfo({
        userInfo: decryptedData,
        session_key,
        skey
      })
    })
    .catch(err => {
      return {
        result: -3,
        errmsg: JSON.stringify(err)
      }
    })
}

/**
 * 获取当前用户session_key
 * @param {*用户临时登录凭证} code 
 * @param {*小程序appid} appid 
 * @param {*小程序密钥} appSecret 
 */
function getSessionKey(code, appid, appSecret) {

  const opt = {
    method: 'GET',
    url: 'https://api.weixin.qq.com/sns/jscode2session',
    params: {
      appid: appid,
      secret: appSecret,
      js_code: code,
      grant_type: 'authorization_code'
    }
  };

  return http(opt).then(function (response) {
    const data = response.data;

    if (!data.openid || !data.session_key || data.errcode) {
      return {
        result: -2,
        errmsg: data.errmsg || '返回数据字段不完整'
      }
    } else {
      console.log('jscode2session结果',data);
      return data
    }

  });
}
module.exports = {
  authorizeMiddleware
}
posted @ 2020-03-29 23:49  草珊瑚  阅读(533)  评论(0编辑  收藏  举报