做一个应用,肯定避免不了登录操作。用户的个人信息啊,相关的收藏列表等功能都需要用户登录之后才能操作。一般我们使用token做标识。
小程序并没有登录界面,使用的是 wx.login 。 wx.login 会获取到一个 code,拿着该 code 去请求我们的后台会最后返回一个token到小程序这边,保存这个值为 token 每次请求的时候带上这个值。
一般还需要把用户的信息带上比如用户微信昵称,微信头像等,这时候就需要使用 wx.getUserInfo ,这里涉及到一个用户授权的问题
带上用户信息就够了嘛? too young too simple!我们的项目不可能只有小程序,相应的微信公众平台可能还有相应的App,我们需要把账号系统打通,让用户在我们的项目中的账户是同一个。这就需要用到微信开放平台提供的 UnionID 。
登陆
//app.js
App({
onLaunch: function () {
console.log('App onLaunch');
var that = this;
// 获取商城名称
wx.request({
url: 'https://api.it120.cc/'+ that.globalData.subDomain +'/config/get-value',
data: {
key: 'mallName'
},
success: function(res) {
wx.setStorageSync('mallName', res.data.data.value);
}
})
this.login();
this.getUserInfo();
},
login : function () {
var that = this;
var token = that.globalData.token;
// 如果有token
if (token) {
// 检查token是否有效
wx.request({
url: 'https://api.it120.cc/' + that.globalData.subDomain + '/user/check-token',
data: {
token: token
},
success: function (res) {
// 如果token失效了
if (res.data.code != 0) {
that.globalData.token = null;
that.login(); // 重新登陆
}
}
})
return;
}
// 【1】调用微信自带登陆
wx.login({
success: function (res) {
// 【2】 拿到code去访问我们的后台换取其他信息
wx.request({
url: 'https://api.it120.cc/'+ that.globalData.subDomain +'/user/wxapp/login',
data: {
code: res.code
},
success: function(res) {
// 如果说这个code失效的
if (res.data.code == 10000) {
// 去注册
that.registerUser();
return;
}
// 如果返回失败了
if (res.data.code != 0) {
// 登录错误
wx.hideLoading();
// 提示无法登陆
wx.showModal({
title: '提示',
content: '无法登录,请重试',
showCancel:false
})
return;
}
// 【3】 如果成功后设置token到本地
that.globalData.token = res.data.data.token;
// 保存用户信息
wx.setStorage({
key: 'token',
data: res.data.data.token
})
}
})
}
})
},
// 注册?? [这个看需求]
registerUser: function () {
var that = this;
wx.login({
success: function (res) {
var code = res.code; // 微信登录接口返回的 code 参数,下面注册接口需要用到
wx.getUserInfo({
success: function (res) {
var iv = res.iv;
var encryptedData = res.encryptedData;
// 下面开始调用注册接口
wx.request({
url: 'https://api.it120.cc/' + that.globalData.subDomain +'/user/wxapp/register/complex',
data: {code:code,encryptedData:encryptedData,iv:iv}, // 设置请求的 参数
success: (res) =>{
wx.hideLoading();
that.login();
}
})
}
})
}
})
},
// 获取用户信息
getUserInfo:function() {
wx.getUserInfo({
success:(data) =>{
this.globalData.userInfo = data.userInfo;
wx.setStorage({
key: 'userInfo',
data: data.userInfo
})
return this.globalData.userInfo;
}
})
},
globalData:{
userInfo:null,
subDomain:"34vu54u7vuiuvc546d",
token: null
}
})
授权问题
getUserInfo: function () {
// 先调用wx.getSetting 获取用户权限设置
wx.getSetting({
success(res) {
console.log('1');
if (!res.authSetting['scope.userInfo']) {
wx.authorize({
scope: 'scope.userInfo',
success() {
// 用户已经同意小程序使用录音功能,后续调用 wx.getUserInfo接口不会弹窗询问
wx.getUserInfo({
success: (data) => {
this.globalData.userInfo = data.userInfo;
wx.setStorage({
key: 'userInfo',
data: data.userInfo
})
return this.globalData.userInfo;
}
})
}
})
} else {
console.log(2);
}
}
})
},
授权2
小程序登录流程
这里引用下官方的一张登录流程图,我就按照登录流程图来讲下我的理解。
第一步
客户端(小程序)获取当前微信登录用户的登录凭证(code)
可通过wx.login api获得。这里有地方需要注意
1.wx.login不会弹授权弹框
2.wx.login换取的code只能使用一次,如果需要新code只能重新调用wx.login接口
wx.login({
success:(res)=>{
let code= res.code
}
})
第二步
通过上一步获得的临时登录凭证传给服务器端获取openid和session_key.服务器端需要通过appid、appsecret、(这里的数据可以从小程序管理后台获得)code(第一步获取到的code)向微信服务端发送请求获取seeeion_key和openid。为了安全。建议将获得的session_key加密后再传给客户端。
第三步
客户端获得加密后的登录态后把登录态存在本地以便后面进行业务请求。由于小程序中不存在cookie机制。所以可以把登录态存储在storage中。
以上就是微信官方登录流程图的一个大体过程。
但是在实际应用中可能要复杂点?我们接下来看。
登录态在实际应用中的维护
这里看一下微信官方的说明
通过 wx.login 接口获得的用户登录态拥有一定的时效性。
用户越久未使用小程序,用户登录态越有可能失效。
反之如果用户一直在使用小程序,则用户登录态一直保持有效。
具体时效逻辑由微信维护,对开发者透明。
开发者只需要调用 wx.checkSession 接口检测当前用户登录态是否有效。
这说明如果用户一直在使用小程序。登录态就不会过期。反之就会过期。这里可以通过wx.checkSession api 来判断登录态是否过期。
接下来上代码。来看下在应用中的登录态维护。
目前在小程序中需要拉起微信登录授权的弹框。需要在wxml文件中调用button组件来调用:如下
<button bindgetuserinfo="getInfo" hover-class="none" open-type="getUserInfo"></button>
这样用户点击按钮的时候会弹出授权获取用户信息的弹窗。用户点击允许我们就可以拿到数据进行登录并进行业务请求。 如果点击拒绝可以获取不需要登录可查看的数据请求,并安利用户拒绝后的结果。重新引导用户进行授权。
下面是用户非首次进入应用的一个登录态维护(首次进入通过button来授权。所以success回调是不会执行的。直接fail的回调。)
// 小程序启动判断用户是否授权,根据是否授权来请求不同的业务数据
wx.getSetting({
success: (res) => {
//用户已授权
if (res.authSetting['scope.userInfo']) {
// 判断登录态是否过期
wx.checkSession({
// 登录态未过期,直接进行业务请求
success: (res) => {
//业务请求代码。。。
},
// 登录态已过期 。重新调用wx.login进行登录换取code
fail: (res) => {
// 可以在这里进行重新登录后的回调
wx.login({
success: function(res) {
let code = res.code;
}
})
}
})
}
// 为授权
else {
// 执行未授权的业务代码
}
}
})
附上登录态过期的回调。
/**
* 登录失败后重新登录
*/
getToken: function(fn) {
let that = this;
let getLogin = new Promise((resolve, reject) => {
//登录获取code
wx.login({
success: function(res) {
var code = res.code;
that.globalData.code = code;
resolve([fn, code]);
},
fail: function(res) {
reject();
}
})
});
getLogin.then(([fn, code]) => {
return new Promise((resolve, reject) => {
//使用该api需要在页面通过button组件触发授权弹窗
wx.getUserInfo({
success: function(res) {
//这里的iv,encryptedData等数据是用来服务器端进行解密的。
let requestData = {
"Data": {
"IV": res.iv,
"EncryptedData": res.encryptedData,
"JsCode": code,
},
}
//发送请求
wx.request({
url: that.apiList.login.getLogin,
data: requestData,
method: "POST",
success: function(res) {
//获取到自定义登录态存入storage
if (res.data && res.data.Success) {
that.globalData.token = res.data.Data.Key;
wx.setStorageSync('LoginSessionKey', res.data.Data.Key);
resolve(fn);
} else {
reject();
}
},
fail: function() {
Hq.tipMaskNoneIcon('您的网络开小差了');
}
})
}
})
});
}).then((fn) => {
that.getCountryInfo(fn);
}, function() {}))
},
//执行fn回调函数
getCountryInfo: function(fn) {
if (typeof fn == 'function') {
//登录成功后进行业务请求。
fn();
} else {
Hq.afterSend();
}
},
以上就是我的一些理解。有语句不通,逻辑不清晰的地方,请不吝留言赐教!