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


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 相关文章推荐
分享10篇优秀的jQuery幻灯片制作教程及应用案例
Apr 16 Javascript
Jqgrid表格随窗口大小改变而改变的简单实例
Dec 28 Javascript
利用js实现在浏览器状态栏显示访问者在本页停留的时间
Dec 29 Javascript
原生js实现复制对象、扩展对象 类似jquery中的extend()方法
Aug 30 Javascript
javascript Deferred和递归次数限制实例
Oct 21 Javascript
使用jquery+CSS实现控制打印样式
Dec 31 Javascript
JavaScript动态设置div的样式的方法
Dec 26 Javascript
js实现数组冒泡排序、快速排序原理
Mar 08 Javascript
简单实现js间歇或无缝滚动效果
Jun 29 Javascript
js通过指定下标或指定元素进行删除数组的实例
Jan 12 Javascript
基于Cookie常用操作以及属性介绍
Sep 07 Javascript
JS实现运动缓冲效果的封装函数示例
Feb 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
ip签名探针
2006/10/09 PHP
php 日期和时间的处理-郑阿奇(续)
2011/07/04 PHP
深入apache host的配置详解
2013/06/09 PHP
php根据日期判断星座的函数分享
2014/02/13 PHP
php 实现Hash表功能实例详解
2016/11/29 PHP
浅谈laravel 5.6 安装 windows上使用composer的安装过程
2019/10/18 PHP
JavaScript中的Array对象使用说明
2011/01/17 Javascript
前端分页功能的实现以及原理(jQuery)
2017/01/22 Javascript
bootstrap中添加额外的图标实例代码
2017/02/15 Javascript
Angular 4 依赖注入学习教程之FactoryProvider的使用(四)
2017/06/04 Javascript
js实现倒计时器自定义时间和暂停
2019/02/25 Javascript
js取0-9随机取4个数不重复的数字代码实例
2019/03/27 Javascript
JavaScript实现无限级递归树的示例代码
2019/03/29 Javascript
Vue 理解之白话 getter/setter详解
2019/04/16 Javascript
三分钟教你用Node做一个微信哄女友(基友)神器(面向小白)
2019/06/21 Javascript
JavaScript复制变量三种方法实例详解
2020/01/09 Javascript
微信小程序实现通讯录列表展开收起
2020/11/18 Javascript
[00:36]TI7不朽珍藏III——斯温不朽展示
2017/07/15 DOTA
Python使用py2exe打包程序介绍
2014/11/20 Python
python下如何查询CS反恐精英的服务器信息
2017/01/17 Python
利用python画一颗心的方法示例
2017/01/31 Python
python中for用来遍历range函数的方法
2018/06/08 Python
Python3 chardet模块查看编码格式的例子
2019/08/14 Python
Window版下在Jupyter中编写TensorFlow的环境搭建
2020/04/10 Python
Python自定义聚合函数merge与transform区别详解
2020/05/26 Python
Python3 pyecharts生成Html文件柱状图及折线图代码实例
2020/09/29 Python
光电信息专业应届生求职信
2013/10/07 职场文书
先进单位事迹材料
2014/12/25 职场文书
公司财务经理岗位职责
2015/04/08 职场文书
2015年六一儿童节活动方案
2015/05/05 职场文书
劳保用品管理制度范本
2015/08/06 职场文书
小学思品教学反思
2016/02/20 职场文书
python基础之模块的导入
2021/10/24 Python
MySQL基于索引的压力测试的实现
2021/11/07 MySQL
基于PyQt5制作一个群发邮件工具
2022/04/08 Python
聊聊CSS粘性定位sticky案例解析
2022/06/01 HTML / CSS