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


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 相关文章推荐
分析 JavaScript 中令人困惑的变量赋值
Aug 13 Javascript
Mootools 1.2教程 正则表达式
Sep 15 Javascript
js中的前绑定和后绑定详解
Aug 01 Javascript
用unescape反编码得出汉字示例
Apr 24 Javascript
Jquery ajax请求导出Excel表格的实现代码
Jun 08 Javascript
AngularJS 指令详细介绍
Jul 27 Javascript
JavaScript运动框架 多物体任意值运动(三)
May 17 Javascript
微信小程序开发之animation循环动画实现的让云朵飘效果
Jul 14 Javascript
基于Vue实现支持按周切换的日历
Sep 24 Javascript
Vue不能检测到Object/Array更新的情况的解决
Jun 26 Javascript
JS调用安卓手机摄像头扫描二维码
Oct 16 Javascript
如何解决.vue文件url引用文件的问题
Jan 18 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面向对象学习笔记之一 基础概念
2012/10/06 PHP
PHP在引号前面添加反斜杠(PHP去除反斜杠)
2013/09/28 PHP
php把数组值转换成键的方法
2015/07/13 PHP
Swoole实现异步投递task任务案例详解
2019/04/02 PHP
繁简字转换功能
2006/07/19 Javascript
jquery 获取json数据实现代码
2009/04/27 Javascript
解决jquery的datepicker的本地化以及Today问题
2012/05/23 Javascript
判定是否原生方法的JS代码
2013/11/12 Javascript
Enter转换为Tab的小例子(兼容IE,Firefox)
2013/11/14 Javascript
js实现目录定位正文示例
2013/11/14 Javascript
javascript里使用php代码实例
2014/12/13 Javascript
微信小程序 生命周期函数详解
2017/05/24 Javascript
vue2 中如何实现动态表单增删改查实例
2017/06/09 Javascript
vue2.x 父组件监听子组件事件并传回信息的方法
2017/07/17 Javascript
基于substring()和substr()的使用以及区别(实例讲解)
2017/12/28 Javascript
Element-ui el-tree新增和删除节点后如何刷新tree的实例
2020/08/31 Javascript
[04:36]DOTA2国际邀请赛 ti3精彩集锦
2013/08/19 DOTA
零基础写python爬虫之抓取百度贴吧并存储到本地txt文件改进版
2014/11/06 Python
在Django的URLconf中进行函数导入的方法
2015/07/18 Python
Python实现注册登录系统
2017/08/08 Python
Python编程二分法实现冒泡算法+快速排序代码示例
2018/01/15 Python
Python pandas常用函数详解
2018/02/07 Python
Python+OpenCV图片局部区域像素值处理改进版详解
2019/01/23 Python
找Python安装目录,设置环境路径以及在命令行运行python脚本实例
2020/03/09 Python
移动端html5 meta标签的神奇功效
2016/01/06 HTML / CSS
localStorage的过期时间设置的方法详解
2018/11/26 HTML / CSS
马德里竞技官方网上商店:Atletico Madrid Shop
2019/03/31 全球购物
会计专业应届生求职信
2013/11/24 职场文书
新书吧创业计划书
2014/01/31 职场文书
小学雷锋月活动总结
2014/07/03 职场文书
2014年会计个人工作总结
2014/11/24 职场文书
逃课检讨书
2015/01/26 职场文书
承诺书模板大全
2015/05/04 职场文书
2015新教师教学工作总结
2015/07/22 职场文书
经典哲理警句:志不真则心不热,心不热则功不贤
2019/11/14 职场文书
浅谈Golang 嵌套 interface 的赋值问题
2021/04/29 Golang