登录

🌈 微信登录流程

登录流程是调wx.login获取code传给后台服务器获取微信用户唯一标识openid及本次登录的会话密钥(session_key)等)。拿到开发者服务器传回来的会话密钥(session_key)之后,前端要保存wx.setStorageSync('sessionKey', 'value')

持久登录状态:session信息存放在cookie中以请求头的方式带回给服务端,放到 request.js 里的 wx.request 的header 里

核心:通过 vuex 的 hasLogin 来判断是进行后续操作,还是跳转到登录页

  1. 程序启动 onLaunch
  2. 判断本地有没有 userInfo 和 userInfo.tel
    1. 有,把 openIdtelunionid 传给后端,换取最新 userInfo,设置 hasLogin = true
      1. openId 在不同应用下唯一
      2. unionid 在同一公司下,不同应用中唯一
    2. 无,设置 hasLogin = false,清空 userInfo,清空 token
  3. 登录页
    1. 通过 wx.login 获取 wxCode
    2. 授权手机号后
      1. wxCode手机号iv手机号encryptedData 发给后端换取 token、tel、userInfo
      2. 设置 登录状态 hasLogin
    3. 跳转回之前登录前的页面
      1. 写个公共跳转 auth 页面的方法
      2. 通过 getCurrentPages()[getCurrentPages().length - 1] 拿到当前页面
onLaunch: function () {
  this.wxLogin()
}
async wxLogin(context) {
  let userInfo = storage.getUserInfo();
  if (userInfo && userInfo.tel) {
    // 有电话,以前登录过,更新 userInfo
    const res = await user.doLoginMobile({
      openid: userInfo.openidApp,
      phone: userInfo.tel,
      unionid: userInfo.unionid,
    });
    if (res.code === 0 && res.data) {
      // 设置vuex登录状态
      context.commit("setHasLogin", true);
      context.commit("setUserInfo", res.data ? res.data : {});
      context.commit("setToken", res.data ? res.data.token : "");
      return context.state.userInfo;
    } else {
      // 登录失败
      // 登出
      context.commit("logout");
      return false;
    }
  } else {
    context.commit("logout");
    return false;
  }
},

// 登出
logout(state) {
  state.userInfo = {};
  state.hasLogin = false;
  storage.removeUserInfo();
  storage.removeToken();
},
// 手机号登录
async weChatLogin() {
  // 获取code
  this.wxCode = await this.getWxCode();

  const data = {
    code: this.wxCode, // 必传
    IV: this.userData.iv, // 必传(手机号的iv)
    encryptedData: this.userData.encryptedData, // 必传(手机号的encryptedData)
  };
  const res = await user.weChatLogin(data);

  if (res.code === 0 && res.data) {
    // 登录成功
    this.setHasLogin(true);
    this.$storage.setToken(res.data.token);
    this.setUserInfo(res.data);
    uni.showToast({ title: "授权登陆成功" });
    setTimeout(() => {
      this.jumpUrl(this.redirectUrl);
    }, 500);
  } else {
    // 登录失败
    uni.showModal({
      title: "登录失败,请重试",
      content: res.msg,
      showCancel: false,
    });
  }
},

🌈 页面跳转拦截

  1. 重写 navigateTo 等跳转方法,使其除了接收 options 对象参数,还接受一个 needAuth
  2. 如果 needAuth 为真,就看下 hasLogin 是否为真
    1. 为真代表已登录,就直接跳转
    2. 为假就代表未登录,跳转登录页
// 对于需要登录才可以进入的页面,先做一下登录校验,如果未登录,则跳转前先跳转至登录页面。
import store from "@/store";
import { gotoAuth } from "@/utils/index";

// 对路由相关的几个方法进行遍历并缓存原方法,
// 在uni对象上重写方法,每个方法增加needAuth参数,表示跳转前是否需要登录
// 如果需要登录,则首先获取用户信息,
// 如果获取不到用户信息,将会自动跳转到登录页(store里面的user模块做的),
// 否则获取到信息就调用缓存起来的原方法,实现跳转 如果不需要登录,则直接调用原方法
export default function () {
  ["navigateTo", "redirectTo", "switchTab", "navigateBack"].map(item => {
    const nativeFunc = uni[item];
    uni[item] = function (opts, needAuth) {
      if (needAuth) {
        // store.dispatch("user/getToken").then(() => {
        //   nativeFunc.call(this, opts);
        // });
        if (store.state.hasLogin) {
          nativeFunc.call(this, opts);
        } else {
          gotoAuth();
        }
      } else {
        return nativeFunc.call(this, opts);
      }
    };
  });
}

数据缓存

🌈 数据缓存

自定义组件