小程序授权逻辑(参考)
## 前言
从最初的一直关注微信小程序(后面简称小程序)的小伙伴应该知道,小程序的授权逻辑底层改了几回,说是为了完善和优化用户体验,那我就想问了,你们来来回回改底层逻辑,那有没有考虑过优化一下我们开发者的体验[发怒][掀桌]???
.... 嗯?
算了,也不说太多了,你都改了,那我们也只能跟着改呗,谁让你牛*,谁让你是微信嘞,咱们宠你,都依你。
## 说明
小程序从一开始的可以直接获取用户信息,到需要用户确认,到最后需要用户主动发起授权,介于这种情况,以及某些模块需要一开始就要获取信息展示等各种因素,故创建一个 `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();
});
}
})
```