小程序授权逻辑(参考)

## 前言 从最初的一直关注微信小程序(后面简称小程序)的小伙伴应该知道,小程序的授权逻辑底层改了几回,说是为了完善和优化用户体验,那我就想问了,你们来来回回改底层逻辑,那有没有考虑过优化一下我们开发者的体验[发怒][掀桌]??? .... 嗯? 算了,也不说太多了,你都改了,那我们也只能跟着改呗,谁让你牛*,谁让你是微信嘞,咱们宠你,都依你。 ## 说明 小程序从一开始的可以直接获取用户信息,到需要用户确认,到最后需要用户主动发起授权,介于这种情况,以及某些模块需要一开始就要获取信息展示等各种因素,故创建一个 `welcome` 启动页,所有进入途径全都经过此界面,相当于是一个入口,便于处理一些必要的信息。 #### 内容 启动页可以设置一个全屏的展示图片,并且在右上角放置一个进入倒计时(一般是5s左右),用于展示某些信息给用户看(其实就是为了避开我们处理那些必要的信息时的空白期,给用户造成不好的体验),至于倒计时纯粹是为了引导用户操作,防止误以为是程序卡死的情况 ## 逻辑处理 小程序进入途径大致分为三种,一个是分享进入、一种是扫码进入、一种是搜索/周边进入。 假设:小程序生命周期函数 `onLoad` 的传参对象是 `options` >i ◆ 分享进入是可以携带参数的,可以根据参数情况,跳转到小程序内部某些页面 ◆ 扫码进入也是可以携带参数,只不过参数是放置在 `options.scene` 中,并且需要调用 `decodeURIComponent` 方法解码。如果你的参数只有一个,并且是数字的话,那解不解码也无所谓了 ◆ 直接搜索或者通过周边进入小程序时,是不会携带任何参数的,所以如果有特别需求的话,需要赋予参数默认值 #### 用户信息授权 先通过接口 `wx.getUserInfo` 判断用户是否已经授过权 如果是已授权模式,那么直接调用授权接口给后端提交授权信息,获取到 sid 后直接保存到 `app.globalData` 中。 如果是未授权模式,那就不管他,跳转到首页去,不过要提前在 `app.globalData` 中存一个 `sid` 的空值,以方便后期传值和判断授权情况。 跳转其它界面之后,如遇到必须获取授权信息才能访问的页面时,判断 `sid` 是否有值。如有,那不用说,直接走流程就好。若没有,那便跳转到登录页面,登录页面包含获取用户信息说明,以及登录按钮和暂不登录按钮,以供用户选择... 登录成功后,返回之前进入的页面继续后面的流程,完事。 ## 代码示例 以下是案例演示,仅供参考,如有兴趣可自行编写逻辑,若有错误或有可优化的地方,欢迎指出。 #### app.js `url`、`request` 函数具体内容,请参考 [接口文档说明](https://easydoc.top/s/52067320/k5QepJMO/cNrJgBek)。 ```Javascript App({ url: { //...}, request: { //...}, getUserInfo: function (user, fn) { let _this = this; user = user.detail || user; if (user.errMsg != 'getUserInfo:ok') return false; wx.setStorageSync('userInfo', user.userInfo); wx.login({ success: function (res) { wx.showLoading({ title: '正在登录...', }) _this.request(['login', { code: res.code }], user, function (res) { _this.globalData.sid = res.data.sid; fn && fn(res); }, 'POST'); } }) }, jointUrl: function (module, arg) { let path = '/pages/' + module + '/' + module, sym = true; for (var i in arg) { path += (sym ? '?' : '&') + i + '=' + arg[i]; } return path; }, globalData: { sid: '', agent_id: 0, //用以判断是否需要在欢迎页等待5s,鉴于小程序右上角'回到首页'按钮作出的兼容措施 playBanner: true } }); ``` #### welcome.js ```Javascript const app = getApp(); var timer = null; Page({ data: { url: '', //需要跳转的路径 time: 5, //在欢迎页等待的时间 }, onLoad: function (options) { let _this = this, url = ''; //若是已授权则直接获取用户信息以作备用 if (!app.globalData.sid) _this.login(); if (options.scene) { // 扫码进入 // 参数值为 scene=hghbsm1406013577%260 let scene = decodeURIComponent(options.scene).split('&'); token = scene[0]; app.globalData.token = token; if(scene[1]) app.globalData.agent_id = scene[1]; url = "/pages/index/index"; } else if (options.token) { // 分享进入 app.globalData.token = options.token; app.globalData.agent_id = options.agent_id; url = app.jointUrl(options.module, options); } else { // 搜索进入 if(app.globalData.agent_id){ url = "/pages/index/index"; }else{ url = "/pages/agent_list/agent_list"; } } wx.setStorageSync('agent_id', app.globalData.agent_id); _this.setData({ url: url }); //启动页倒计时 timer = setInterval(function () { if (_this.data.time <= 0) { _this.immediate(); return false; } _this.setData({ time: --_this.data.time }) }, 1000); }, immediate: function () { app.globalData.playBanner = false; clearInterval(timer); wx.redirectTo({ url: this.data.url, }) }, // 授权登录接口 login: function () { let _this = this, url = this.data.url, token = this.data.token; wx.login({ success: function (res) { let code = res.code; _this.setData({ code: code}); wx.getUserInfo({ success: function (res) { _this.getUserInfo(res); } }) } }); }, //若用户已授权,则直接获取用户信息,传递给后端交换 sid,若未授权,则不做处理,等待倒计时或手动进入下个界面 getUserInfo: function (res) { let _this = this, url = this.data.url, code = this.data.code; wx.setStorageSync('userInfo', res.userInfo); wx.request({ method: 'post', url: app.url('login', { 'code': code }), data: res, success: function (res) { if (res.data.status == 0) { app.globalData.sid = res.data.sid; _this.config(); } } }) }, //需要提前获取某些参数,用以下个界面 config: function(){ let url = this.data.url; app.request('config', function (res) { let msg = res.data.msg, layout = msg.config.settings.layout; app.globalData.singleRow = layout == 0 ? false : layout == 2 ? 2 : true; app.globalData.navLayout = msg.config.settings.nav_layout || 0; wx.redirectTo({ url: url, }); }); } }); ``` #### login.js 登录界面,应小程序官方要求,不能强制用户登录并且要给用户拒绝的权利,所以在那些必须获取用户信息的界面中添加登录功能,列如:个人中心、我的订单、购物车等 ```Javascript const app = getApp(); Page({ data: { code: '', //临时登录凭证 module: '', //切换进登录界面的 页面名称 options: {},//页面参数 }, onLoad: function (options) { let _this = this, module = options.module; this.setData({ module: module, options: options }) console.log('app globalData:', app.globalData); // 检查登录态 wx.checkSession({ success: function () { let sid = app.globalData.sid; if (sid) { //获取用户openid app.request('_openid', { sid: sid, ischeck: 1}, function(res){ if (res.data.status == '10001') { _this.login(); return false; } _this.route(); }); } else { _this.login(); } }, fail: function () { _this.login(); } }); }, //路由跳转 route: function(){ let module = this.data.module; if (module) { wx.redirectTo({ url: app.jointUrl(module, this.data.options) }) } else { wx.navigateBack({ delta: 1 }) } }, // 授权登录接口 login: function () { let _this = this; wx.login({ success: function (res) { _this.setData({ code: res.code }) wx.getUserInfo({ success: function (res) { // console.log('getUserInfo:', res); wx.showLoading({ title: '正在登录...', mask: true }) _this.getUserInfo(user); } }) } }); }, //获取用户信息授权 getUserInfo: function (user) { let _this = this; app.getUserInfo(user, function(res){ _this.route(); }); } }) ```