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


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 相关文章推荐
jquery中输入验证中一个不错的效果
Aug 21 Javascript
Eval and new funciton not the same thing
Dec 27 Javascript
学习JavaScript正则表达式
Nov 13 Javascript
轻松掌握JavaScript单例模式
Aug 25 Javascript
ES6教程之for循环和Map,Set用法分析
Apr 10 Javascript
vue中使用refs定位dom出现undefined的解决方法
Dec 21 Javascript
详解如何在vue项目中引入elementUI组件
Feb 11 Javascript
详解vue移动端日期选择组件
Feb 22 Javascript
vue实现裁切图片同时实现放大、缩小、旋转功能
Mar 02 Javascript
一文快速详解前端框架 Vue 最强大的功能
May 21 Javascript
JavaScript交换两个变量方法实例
Nov 25 Javascript
js实现简单扫雷
Nov 27 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
mysql limit查询优化分析
2008/11/12 PHP
php实现可以设置中奖概率的抽奖程序代码分享
2014/01/19 PHP
Ubuntu12下编译安装PHP5.3开发环境
2015/03/27 PHP
Yii编程开发常见调用技巧集锦
2016/07/15 PHP
php中的异常和错误浅析
2017/05/03 PHP
PHP实现的pdo连接数据库并插入数据功能简单示例
2019/03/30 PHP
jQuery 追加元素的方法如append、prepend、before
2014/01/16 Javascript
禁用Enter键表单自动提交实现代码
2014/05/22 Javascript
简单理解vue中el、template、replace元素
2016/10/27 Javascript
jquery二级目录选中当前页的css样式
2016/12/08 Javascript
基于Vue如何封装分页组件
2016/12/16 Javascript
js实现文字选中分享功能
2017/01/25 Javascript
Node.js搭建WEB服务器的示例代码
2018/08/15 Javascript
React如何解决fetch跨域请求时session失效问题
2018/11/02 Javascript
详解微信小程序调用支付接口支付
2019/04/28 Javascript
微信小程序动态评分展示/五角星展示/半颗星展示/自定义长度展示功能的实现
2020/07/22 Javascript
Vue解决echart在element的tab切换时显示不正确问题
2020/08/03 Javascript
js实现批量删除功能
2020/08/27 Javascript
uniapp电商小程序实现订单30分钟倒计时
2020/11/01 Javascript
linux 下实现python多版本安装实践
2014/11/18 Python
Python学习笔记之if语句的使用示例
2017/10/23 Python
java中两个byte数组实现合并的示例
2018/05/09 Python
python 请求服务器的实现代码(http请求和https请求)
2018/05/25 Python
python实现全排列代码(回溯、深度优先搜索)
2020/02/26 Python
python shapely.geometry.polygon任意两个四边形的IOU计算实例
2020/04/12 Python
Keras:Unet网络实现多类语义分割方式
2020/06/11 Python
jupyter使用自动补全和切换默认浏览器的方法
2020/11/18 Python
让IE可以变相支持CSS3选择器
2010/01/21 HTML / CSS
床上用品全球在线购物:BeddingInn
2016/12/18 全球购物
Luxplus瑞典:香水和美容护理折扣
2018/01/28 全球购物
毕业寄语大全
2014/04/09 职场文书
干部选拔任用方案
2014/05/26 职场文书
县政府办公室领导班子对照检查材料思想汇报
2014/09/28 职场文书
单位介绍信格式
2015/01/31 职场文书
自考生自我评价
2019/06/21 职场文书
JS数组方法some、every和find的使用详情
2021/10/05 Javascript