微信小程序非跳轉式組件受權登陸

首先附上官方文檔地址和受權流程
官方地址:https://developers.weixin.qq....
流程圖:html

大體邏輯:受權 -> 發送code到服務器獲取session_key - > 保存在小程序緩存內 -> 調用wx.getUserInfo和session_key獲取用戶信息 -> 登陸成功返回訪問token -> 記錄登陸狀態 -> 執行登陸成功監聽(失敗則不監聽)
直接上代碼,一下均爲小程序組件模式有興趣的能夠看下官方文檔vue

建立components(自定義名稱)文件夾pages文件夾同級主要放置組件文件git

建立 authorize (自定義名稱)文件夾 仍是同樣的建立 對應的authorize.js ,authorize.wxml .authorize.wxss,authorize.json特別注意這裏的 authorize.json 文件裏面要定義當前頁面爲組件github

{json

"component": true

}
到這裏準備工做完成小程序

authorize.js 換成組件的寫法,具體參考小程序官方文檔,這裏展現我定義的微信小程序

Component({
    //組件的對外屬性 說的確實很官方,用過vue組件的就很容易理解這點
    //父級向子級傳值這裏就是接收值得地方
  properties:{
      //名稱要和父級綁定的名稱相同
      //這裏主要是控制自動受權彈框是否顯示 true=隱藏 false=顯示
    iShidden:{
      type:Boolean,//定義類型
      value: true,//定義默認值
    },
    //是否自動登陸 這裏主要用於沒有受權是否自動彈出受權提示框 
    //**用在不自動登陸頁面可是某些操做須要受權登陸**
    isAuto:{
      type: Boolean,
      value: true,
    },
  },
  //組件的內部數據,和 properties 一同用於組件的模板渲染
  data:{
    cloneIner:null
  },
  //組件所在頁面的生命週期聲明對象
  pageLifetimes:{
      //頁面隱藏
      hide:function(){
      //關閉頁面時銷燬定時器
      if(this.data.cloneIner) clearInterval(this.data.clearInterval);
    },
    //頁面打開
    show:function(){
      //打開頁面銷燬定時器
      if (this.data.cloneIner) clearInterval(this.data.clearInterval);
    },
  },
  //組件生命週期函數,在組件實例進入頁面節點樹時執行
  attached(){
      
  },
  //組件的方法 
  methods:{
  
  }
  });

注:如下的方法都需寫在 methods 內api

第一步:未受權用戶判斷是否執行受權仍是直接進行獲取用戶信息數組

//檢測登陸狀態並執行自動登陸
   setAuthStatus(){
     var that = this;
     that.setErrorCount();
     wx.getSetting({
       success(res) {
       //這裏會檢測是否受權,若是受權了會直接調用自動登陸
         if (!res.authSetting['scope.userInfo']) {
           //沒有受權不會自動彈出登陸框
           if (that.data.isAuto === false) return; 
           //自動彈出受權 
           that.setData({ iShidden: false });
         } else {
           //自動登陸
           that.setData({ iShidden: true });
           if (app.globalData.token) {
           //這裏是受權回調
             that.triggerEvent('onLoadFun', app.globalData.token);
             that.WatchIsLogin();
           } else {
             wx.showLoading({ title: '正在登陸中' });
             //這裏是已受權調用wx.getUserInfo
             that.getUserInfoBydecryptCode();
           }
         }
       }
     })
   }

第二步,沒有受權執行打開受權彈出框緩存

//受權
    setUserInfo(e){
      var that = this, pdata={};
      pdata.userInfo = e.detail.userInfo;
      pdata.spid = app.globalData.spid;
      wx.showLoading({ title: '正在登陸中' });
      wx.login({
        success: function (res) {
          if (!res.code) return app.Tips({ title: '登陸失敗!' + res.errMsg});
          //獲取session_key並緩存
          that.getSessionKey(res.code, function () {
            that.getUserInfoBydecryptCode();
          });
        },
        fail() {
          wx.hideLoading();
        }
      })
    },
    //從緩存中獲取session_key,若是沒有則請求服務器再次緩存
    getSessionKey(code,successFn,errotFn){
      var that=this;
      wx.checkSession({
        success: function (res){
          if(wx.getStorageSync('session_key'))
            successFn && successFn();
          else
            that.setCode(code, successFn, errotFn);
        },
        fail:function(){
          that.setCode(code, successFn, errotFn);
        }
      });
    },
    //訪問服務器得到session_key 並存入緩存中
    setCode(code, successFn, errotFn){
      var that = this;
      app.basePost(app.U({ c: 'Login', a: 'setCode' }), { code: code }, function (res) {
        wx.setStorageSync('session_key', res.data.session_key);
        successFn && successFn(res);
      }, function (res) {
        if (errotFn) errotFn(res);
        else return app.Tips({ title: '獲取session_key失敗' });
      });
    }

第三步:執行getUserInfoBydecryptCode 登陸獲取訪問權限

getUserInfoBydecryptCode: function () {
      var that = this;
      var session_key = wx.getStorageSync('session_key')
      //沒有獲取到session_key,打開受權頁面
      //這裏必須的判斷存在緩存中的session_key是否存在,由於在第一步的時候,判斷了
      //受權了將自動執行獲取用戶信息的方法
      if (!session_key) {
        wx.hideLoading();
        if(that.data.isAuto) that.setData({ iShidden: false })
        return false;
      };
      wx.getUserInfo({
        lang: 'zh_CN',
        success: function (res) {
          var pdata = res;
          pdata.userInfo = res.userInfo;
          pdata.spid = app.globalData.spid;//獲取推廣人ID
          pdata.code = app.globalData.code;//獲取推廣人分享二維碼ID
          if (res.iv) {
            pdata.iv = encodeURI(res.iv);
            pdata.encryptedData = res.encryptedData;
            pdata.session_key = session_key;
            //獲取用戶信息生成訪問token
            app.basePost(app.U({ c: 'login', a: 'index' }), { info: pdata},function(res){
              if (res.data.status == 0) return app.Tips(
                { title: '抱歉,您已被禁止登陸!' }, 
                { tab: 4, url: '/pages/login-status/login-status' }
                );
              else if(res.data.status==410){
                wx.removeStorage({ key:'session_key'});
                wx.hideLoading();
                if (that.data.iShidden == true) that.setData({ iShidden: false });
                return false;
              }
              //取消登陸提示
              wx.hideLoading();
              //關閉登陸彈出窗口
              that.setData({ iShidden: true, ErrorCount:0});
              //保存token和記錄登陸狀態
              app.globalData.token = res.data.token;
              app.globalData.isLog = true;
              //執行登陸完成回調
              that.triggerEvent('onLoadFun', app.globalData.uid);
              //監聽登陸狀態
              that.WatchIsLogin();
            },function(res){
              wx.hideLoading();
              return app.Tips({title:res.msg});
            });
          } else {
            wx.hideLoading();
            return app.Tips({ title: '用戶信息獲取失敗!'});
          }
        },
        fail: function () {
          wx.hideLoading();
    that.setData({ iShidden: false });
        },
      })
    }

第四步:監聽登陸狀態
再服務器沒法獲取到token時,當前頁面會一直監聽token是否爲空,防止無限獲取token設置錯誤次數,終止監聽

監聽token的用意爲:token是服務器返回當前用戶的訪問憑證,憑證有過時的時候這時候全部的網絡請求將沒法訪問,因此用了一個愚蠢的方法來監聽token

//監聽登陸狀態
    WatchIsLogin:function(){
      this.data.cloneIner=setInterval(function(){
        //防止死循環,超過錯誤次數終止監聽
        if (this.getErrorCount()) return clearInterval(this.data.clearInterval);
        if (app.globalData.token == '') this.setAuthStatus();
      }.bind(this),800);
      this.setData({ cloneIner:this.data.cloneIner});
    }
 /**
     * 處理錯誤次數,防止死循環
     * 
    */
    setErrorCount:function(){
      if (!this.data.ErrorCount) this.data.ErrorCount=1;
      else this.data.ErrorCount++;
      this.setData({ ErrorCount: this.data.ErrorCount});
    },
    /**
     * 獲取錯誤次數,是否終止監聽
     * 
    */
    getErrorCount:function(){
      return this.data.ErrorCount >= 10  ?  true : false;
    }

以上就是組件內所有的方法須要在組件生命週期函數內調用第一步的方法檢測受權,執行登陸

attached(){
    this.setAuthStatus();
  }

注:在網絡請求中必定要處理token失效的操做,主要把 app.globalData.token和app.globalData.isLog 設置回空和false

這裏附上沒有定義的一些app內公用的快捷方法如下的方法最好是寫在其餘文件裏面在app.js裏面寫一個快捷調用的方法

/*
* post網絡請求 
* @param string | object 請求地址
* @param object data POST請求數組
* @param callable successCallback 成功執行方法
* @param callable errorCallback 失敗執行方法
*/
const basePost = function (url, data, successCallback, errorCallback, header) {
  if (typeof url == 'object') url = U(url);
  wx.request({
    url: url,
    data: data,
    dataType  : 'json',
    method: 'POST',
    header: header,
    success: function (res) {
      try{
        if (res.data.code == 200) {
          successCallback && successCallback(res.data);
        } else {
          if (res.data.code == 402) getApp().globalData.token = '', getApp().globalData.isLog = false;
          //返回狀態爲401時,用戶被禁止訪問 關閉當前全部頁面跳轉至用戶禁止登陸頁面
          if (res.data.code == 401) return Tips({ title: res.data.msg}, { tab: 4, url:'/pages/login-status/login-status'});
          errorCallback && errorCallback(res.data);
        }
      } catch (e) {
        console.log(e);
      }
    }, fail: function (res) {
      errorCallback && errorCallback(res);
    },
    complete: function (res) {

    }
  });
}
/*
* 組裝URl
*@param object opt 
*/
const U = function (opt, url) {
  var m = opt.m || 'routine_two', c = opt.c || 'auth_api', a = opt.a || 'index', q = opt.q || '',
    p = opt.p || {}, params = '', gets = '';
  if (url == undefined) url=getApp().globalData.url;
  params = Object.keys(p).map(function (key) {
    return key + '/' + p[key];
  }).join('/');
  gets = Object.keys(q).map(function (key) {
    return key + '=' + q[key];
  }).join('&');
  return url + '/' + m + '/' + c + '/' + a + (params == '' ? '' : '/' + params) +'.html'+ (gets == '' ? '' : '?' + gets);
}

代碼量有點多,都是能用到的,望大神們多多指點

本小程序後臺框架由 http://github.crmeb.net/u/blue 提供 TP5+EasyWeChat技術支持若是對微信小程序受權不熟悉的能夠用 EasyWeChat,確實好用;不是來吹這個EasyWeChat來了,只是我的以爲好用勿噴

相關文章
相關標籤/搜索