小程序登录
登录流程时序(重点)
说明
- 调用
wx.login()
获取 临时登录凭证code ,并回传到开发者服务器。 - 调用
auth.code2Session
接口,换取 用户唯一标识 OpenID 和 会话密钥 session_key。
之后开发者服务器可以根据用户标识来生成自定义登录态,用于后续业务逻辑中前后端交互时识别用户身份。
注意
- 会话密钥
session_key
是对用户数据进行加密签名
的密钥。为了应用自身的数据安全,开发者服务器不应该把会话密钥下发到小程序,也不应该对外提供这个密钥。 - 临时登录凭证 code 只能使用一次
前置知识点
1、wx.checkSession(Object object)
检查登录态是否过期。
通过 wx.login 接口获得的用户登录态拥有一定的时效性。用户越久未使用小程序,用户登录态越有可能失效。反之如果用户一直在使用小程序,则用户登录态一直保持有效。具体时效逻辑由微信维护,对开发者透明。开发者只需要调用 wx.checkSession 接口检测当前用户登录态是否有效。
登录态过期后开发者可以再调用 wx.login 获取新的用户登录态。调用成功说明当前 session_key 未过期,调用失败说明 session_key 已过期。
参数(红色框为常用)
示例代码
wx.checkSession({
successs() {
// sesssion_key未过期,并且在本生命周期一直有效
},
fail() {
// session_key已经失效,需要重新执行登录流程
wx.login() // 重新登录
}
})
2.wx.login(Object object)
调用接口获取登录凭证(code)。通过凭证进而换取用户登录态信息,包括用户的唯一标识(openid)及本次登录的会话密钥(session_key)等。用户数据的加解密通讯需要依赖会话密钥完成。
参数(红色框为常用)
示例代码
wx.login({
success(res) {
if(res.code) {
// 发起网络请求
wx.request({
url: 'https://test.com/onLogin',
data: {
code: res.code
}
})
} else {
console.log('登录失败!' + res.errMsg)
}
}
})
3.auth.code2Session
本接口应在服务器端调用。
登录凭证校验。通过wx.login
接口获得临时登录凭证 code 后传到开发者服务器调用此接口完成登录流程。
请求地址
GET https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code
请求参数(红色框为必备)
返回值(红色框为常用)
4.wx.request(Object object)
示例代码
wx.request({
url: 'test.php', // 示例接口
data: {
x:'',
y: ''
},
header: {
'content-type': 'applicatin/json' //默认值
},
success(res) {
console.log(res.data)
}
})
具体详情请看:
https://developers.weixin.qq.com/miniprogram/dev/api/network/request/wx.request.html
实际代码示例流程
第一步:(小程序)新建Api
目录
代码实例
const apiHttp = "http://192.168.0.104:7001"; // 后端IP地址
// 请求
function request(url, method, data, header) {
data = data || {};
header = header || {};
let token = wx.getStorageSync("token"); // 在本地缓存中获取token
if(token) {
if(!header || !header["Authorization"]) {
header["Authorization"] = token;
}
}
wx.showNavigationBarLoading(); // 在当前页面显示导航条加载动画
let promise = new Promise(function(resolve, reject) {
wx.request({
url: apiHttp + url,
header: header,
data: data,
method: method,
success: function(res) {
// 开发者服务器返回的 HTTP 状态码
if(res.statusCode == 401) { // token过期,重新执行登录流程
reLogin().then(() => {
resolve();
}).catch(reason => {
console.log(reason);
})
}
resolve(res);
},
fail: reject,
complete: function() {
wx.hideNavigationBarLoading();
}
})
})
return promise;
}
// 重新登录
function reLogin() {
return new Promise((resolve, reject) => {
// 先移除已存在的token
wx.removeStorageSync('token');
wx.showToast({
title: '登录信息过期',
icon: "none",
duration: 1000 // 持续时间
})
setTimeout(() => {
wx.showLoading({ // 显示 loading 提示框。需主动调用 wx.hideLoading 才能关闭提示框
title: '重新登录中',
mask: true, // 是否显示透明蒙层,防止触摸穿透
success: function() {
wx.login({
success: res => {
request('/user/login',"POST",{
code: res.code
}).then(res => {
wx.hideLoading();
if(res.statusCode == 200) {
let token = res.data.token;
wx.setStorageSync('token',token);
wx.showToast({
title: '登陆成功',
icon: 'success'
})
resolve();
} else {
reject(res.data.msg);
}
})
}
})
}
})
}, 1000)
})
}
module.exports = {
apiHttp: apiHttp,
"post": function(url, data, header) {
return request(url, "POST", data, header);
}
}
第二步:(小程序)app.js
const request = require('/api/index.js');
App({
login: function() {
const that = this;
return new Promise((resolve, reject) => {
wx.checkSession({
success() {
// session_key 未过期,并且在本生命周期一直有效;
resolve();
},
fail() {
// session_key 已经失效,需要重新执行登录流程
wx.login({
success: res => {
// 发送res.code到后台换取openId,sessionKey,unionId
request.post('/user/login', {
code: res.code
}).then(res => {
let token = res.data.token;
wx.setStorageSync('token', token);
resolve();
})
}
})
}
})
})
}
})
第三步:(后端Egg)router.js
'use strict';
/**
* @param {Egg.Application} app - egg application
*/
module.exports = app => {
const { router, controller } = app;
// 用户登录
router.post('/user/login', controller.user.login);
}
第四步:(后端Egg)controller/user.js
'use strict';
const Controller = require('egg').Controller;
class UserController extends Controller {
async login() {
const { ctx } = this;
/**小程序调用wx.login()获取临时登录凭证code ,并传给后台,后台以code换取 用户唯一标识openid 和 会话密钥session_key*/
const code = ctx.request.body.code;
const resData = await ctx.service.user.login(code);
// 判断当前openid是否存在数据库,没有则创建
const userInfo = await ctx.model.User.findByPk(resData.openid,{raw: true});
if(!userInfo) {
await ctx.service.user.create(resData);
}
const token = await this.app.jwt.sign({ openid:resData.openid }, this.app.config.jwt.secret, { expiresIn: "24h" });
ctx.status = 200;
ctx.body = {
msg: '登录成功!',
token
}
}
}
module.exports = UserController;
第五步:(后端Egg)service/user.js
'use strict';
// 引入axios插件
const axios = require('axios');
const Service = require('egg').Service;
class UserService extends Service {
// 登录
async login(code) {
const resData = await axios.get('https://api.weixin.qq.com/sns/jscode2session?appid=' + this.config.appid + '&secret=' + this.config.secret + '&js_code=' + code + '&grant_type=authorization_code');
if(resData.status == 200) {
return resData.data
} else {
this.ctx.status = 500;
this.ctx.body = {
msg: '服务器发生错误'
}
}
}
// 创建用户
async create(userInfo) {
await this.ctx.model.User.create(userInfo);
return;
}
}
第六步:(后端Egg)model/user.js
//用户表
module.exports = app => {
const { STRING } = app.Sequelize;
const User = app.model.define('user', {
openid: { type:STRING(50), allowNull:false, primaryKey:true, unique:true, comment:"用户唯一标识" },
session_key: { type:STRING(50), allowNull:false, comment:"会话密钥" },
nickName: { type:STRING(30), comment:"发布者名" },
avatarUrl: { type:STRING(150), comment:"用户头像" },
signature: { type:STRING(30), comment:"个性签名" }
});
return User;
};
以上就是小程序登录流程,觉得有用的博友给个star!!!