资讯专栏INFORMATION COLUMN

微信小程序非跳转式组件授权登录

Leo_chen / 1487人阅读

摘要:首先附上官方文档地址和授权流程官方地址流程图大致逻辑授权发送到服务器获取保存在小程序缓存内调用和获取用户信息登录成功返回访问记录登录状态执行登录成功监听失败则不监听直接上代码,一下均为小程序组件模式有兴趣的可以看下官方文档创建自

首先附上官方文档地址和授权流程
官方地址:https://developers.weixin.qq....
流程图:

大致逻辑:授权 -> 发送code到服务器获取session_key - > 保存在小程序缓存内 -> 调用wx.getUserInfo和session_key获取用户信息 -> 登录成功返回访问token -> 记录登录状态 -> 执行登录成功监听(失败则不监听)
直接上代码,一下均为小程序组件模式有兴趣的可以看下官方文档

创建components(自定义名称)文件夹pages文件夹同级主要放置组件文件

创建 authorize (自定义名称)文件夹 还是一样的创建 对应的authorize.js ,authorize.wxml .authorize.wxss,authorize.json特别注意这里的 authorize.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 内

第一步:未授权用户判断是否执行授权还是直接进行获取用户信息

//检测登录状态并执行自动登录
   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来了,只是个人觉得好用勿喷

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/31558.html

相关文章

  • 信小程序开发中的二三事之网易云信IMSDK DEMO

    摘要:传统的网页编程采用的三剑客来实现,在微信小程序中同样有三剑客。观察者模式不难实现,重点是如何在微信小程序中搭配其特有的生命周期来使用。交互事件传统的事件传递类型有冒泡型与捕获型,微信小程序中自然也有。 本文由作者邹永胜授权网易云社区发布。 简介为了更好的展示我们即时通讯SDK强悍的能力,网易云信IM SDK微信小程序DEMO的开发就提上了日程。用产品的话说就是: 云信 IM 小程序 S...

    weij 评论0 收藏0
  • 信小程序为例学习网站开发平台API调用

    摘要:二开发工具与资源平台微信开发者工具主要用于敲网页代码,但是最主要用来进行网页效果预览。八总结以上微信小程序旨在实现一些基本功能,也存在一些不合理之处,如对项目有疑问或不同见解的同仁可与本人联系邮箱。 一、引言 相信各位码农们都有过要调用各大资源网站提供的API的经历,但是在接入的时候出现许多这样那样的问题,最近在做一个业界备受关注的微信小程序项目,使用了多个网站的API接入,接...

    jackwang 评论0 收藏0
  • 优雅解决信小程序授权登录需要button触发

    摘要:优雅解决微信小程序授权登录需要触发聊一聊最近的一个项目,这个项目是一个收书售书的小程序,有商城专栏信息发布论坛等功能。微信不会把的有效期告知开发者。 优雅解决微信小程序授权登录需要button触发 聊一聊最近的一个项目,这个项目是一个收书、售书的小程序,有商城、专栏、信息发布论坛等功能。虽然不是面向所有用户,但要求无论用户是否授权都皆可使用,但同时也要求部分功能对不授权的用户限制开放。...

    plus2047 评论0 收藏0
  • 记录信小程序的坑

    摘要:除官方外的参考文章微信小程序实例创建下发模板消息实例手把手教你开发微信小程序之模版消息开发教你突破小程序模板消息的推送限制获取用户信息接口的废弃问题接口是获取用户信息昵称,头像等的接口,在官方文档上写是即将废弃。 ----------------更新-------------- 2018年10月10日官网3个接口废弃的通知: 1、分享监听接口分享消息给好友时,开发者将无法从callba...

    EastWoodYang 评论0 收藏0
  • 信小程序之启动页的重要性

    摘要:在小程序启动的时候自动登录,目前没获取用户信息,所以不需要用户授权,这个逻辑放在根目录下的的方法中。做完之后发现了一个很严重的问题,就是的方法确实会在小程序启动的时候执行,但是首页也会是在文件的中第一个页面也会同时执行,它不是阻塞的。 启动页在APP中是个很常见的需求,为什么对于小程序来说也非常重要呢?首先我描述一下我在开发过程中遇到的一些问题以及解决的步骤,到最后为什么要加启动页,看...

    Alan 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<