微信小程序非跳转式组件授权登录的方法示例


Posted in Javascript onMay 22, 2019

首先附上官方文档地址和授权流程

官方地址:https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/login.html

流程图:

大致逻辑:授权 -> 发送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来了,只是个人觉得好用勿喷

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
5 cool javascript apps
Mar 24 Javascript
DOM2非标准但却支持很好的几个属性小结
Jan 21 Javascript
javasript实现密码的隐藏与显示
May 08 Javascript
用JavaScript实现PHP的urlencode与urldecode函数
Aug 13 Javascript
基于OL2实现百度地图ABCD marker的效果
Oct 01 Javascript
JS集成fckeditor及判断内容是否为空的方法
May 27 Javascript
JS判断来路是否是百度等搜索索引进行弹窗或自动跳转的实现代码
Oct 09 Javascript
浅述Javascript的外部对象
Dec 07 Javascript
Angular的MVC和作用域
Dec 26 Javascript
H5图片压缩与上传实例
Apr 21 Javascript
详解webpack之图片引入-增强的file-loader:url-loader
Oct 08 Javascript
vuex管理状态 刷新页面保持不被清空的解决方案
Nov 11 Javascript
小程序rich-text组件如何改变内部img图片样式的方法
May 22 #Javascript
JavaScript中的 new 命令
May 22 #Javascript
element-ui组件中input等的change事件中传递自定义参数
May 22 #Javascript
原生JS实现列表内容自动向上滚动效果
May 22 #Javascript
小程序如何使用分包加载的实现方法
May 22 #Javascript
原生js实现trigger方法示例代码
May 22 #Javascript
koa router 多文件引入的方法示例
May 22 #Javascript
You might like
PHP开发需要注意的安全问题
2010/09/01 PHP
PHP计划任务、定时执行任务的实现代码
2011/04/23 PHP
php根据日期判断星座的函数分享
2014/02/13 PHP
实例介绍PHP删除数组中的重复元素
2019/03/03 PHP
IE8 下的Js错误HTML Parsing Error...
2009/08/14 Javascript
js 编程笔记 无名函数
2011/06/28 Javascript
如何获取select下拉框的值(option没有及有value属性)
2013/11/08 Javascript
javascript表单验证使用示例(javascript验证邮箱)
2014/01/07 Javascript
JavaScript关闭当前页面(窗口)不带任何提示
2014/03/26 Javascript
jquery插件bxslider用法实例分析
2015/04/16 Javascript
JS基于面向对象实现的放烟花效果
2015/05/07 Javascript
jQuery+html5+css3实现圆角无刷新表单带输入验证功能代码
2015/08/21 Javascript
基于javascript实现最简单的选项卡切换效果
2016/05/16 Javascript
JavaScript实现的冒泡排序法及统计相邻数交换次数示例
2017/04/26 Javascript
AngularJs+Bootstrap实现漂亮的计算器
2017/08/10 Javascript
JS/jQuery实现超简单的Table表格添加,删除行功能示例
2019/07/31 jQuery
layui弹出框Tab选项卡的示例代码
2019/09/04 Javascript
在NodeJs中使用node-schedule增加定时器任务的方法
2020/06/08 NodeJs
Jquery 获取相同NAME 或者id删除行操作
2020/08/24 jQuery
[01:28:31]《加油DOTA》真人秀 第五期
2014/09/01 DOTA
[39:02]DOTA2亚洲邀请赛 3.31 小组赛 B组 Mineski vs VGJ.T
2018/04/01 DOTA
python正则分组的应用
2013/11/10 Python
Django中login_required装饰器的深入介绍
2017/11/24 Python
numpy.array 操作使用简单总结
2019/11/08 Python
在python中使用pyspark读写Hive数据操作
2020/06/06 Python
澳大利亚巧克力花束和礼品网站:Tastebuds
2019/03/15 全球购物
俄罗斯运动、健康和美容产品在线商店:Lactomin.ru
2020/07/23 全球购物
文明工地标语
2014/06/16 职场文书
片区教研活动总结
2014/07/02 职场文书
品牌推广活动策划方案
2014/08/19 职场文书
个人租房协议书(范本)
2014/10/14 职场文书
高中校园广播稿
2014/10/21 职场文书
年会邀请函范文
2015/01/30 职场文书
写给媳妇的检讨书
2015/05/06 职场文书
长征观后感
2015/06/09 职场文书
如何解决php-fpm启动不了问题
2021/11/17 PHP