今天学习了微信小程序的登录注册,下面就是把我的思路以及做法写下来。
前提:本案例是配合API工厂的后台接口实现的
一、流程图(看一张流程图来了解怎么实现登录注册)
前端开发需要做的任务就是从小程序到开发者服务器这一条线路的工作流程,
开发者服务器到微信接口服务是后台人员的解密拿openid和session_key的工作。
首次登录:
1、首先需要调用小程序api接口 wx.login() 获取 临时登录凭证code ,这个code是有过期时间的。
2、将这个code回传到开发者服务器(就是请求开发者服务器的登录接口,通过凭证进而换取用户登录态信息,包括用户的唯一标识(openid)及本次登录的会话密钥(session_key)等)。
3、拿到开发者服务器传回来的会话密钥(session_key)之后,前端要保存wx.setStorageSync(‘sessionKey’, ‘value’)
注:其实说白了就是,在微信接口也就是后台,拿到我们需要的coke,iv,appecrct,并将它保存在开发者服务器,获取到coke等信息后并判断其是否过期,然后就是调用封装好的接口。
再次登录的时候,就要判断存储的session_key是否过期了:
1、获取缓存中的session_key,wx.getStorageSync(‘sessionKey’)
2、如果缓存中存在session_key,那么调用小程序api接口wx.checkSession()来判断登录态是否过期,回调成功说明当前 session_key 未过期,回调失败说明 session_key 已过期。登录态过期后前端需要再调用 wx.login()获取新的用户的code,然后再向开发者服务器发起登录请求。
3、一般在项目开发,开发者服务器也会对用户的登录态做过期限制,所以这时在判断完微信服务器中登录态如果没有过期之后还要判断开发者服务器的登录态是否过期。(请求开发者服务器给定的接口进行请求判断就好)。
4、无论是微信服务器过期了还是开发者服务器登录态过期了,都要像首次登录那样开始三步骤。所以注意封装代码。
二、效果视频
二、代码实现
首先是给页面加上一个弹出层,在弹出层上有一个点击允许的按钮和暂不登录的按钮。(注意,在这里我的弹出层是一个组件)
组件:(文件夹名:xhy_user_dialog下有四个文件,分别是.wxss、.wxml、js、json)
在.wxml文件
<button type="primary" open-type="getUserInfo" bindgetuserinfo="getUserinfo">允许</button>
<button type="default" catchtap="getUserinfo">暂不登录</button>
js组件
思路:给这两个按钮一个点击事件,允许这个按钮因为有open-type
这个事件,所以这两个按钮可以设置同一个事件,但是获取的数据有一点不太一样。因此可以同时用一个事件。
// components/xhy_user_dialog/xhy_user_dialog.js
Component({
/**
* 组件的属性列表
*/
properties: {
"img":{
type:String,
value:"/assets/user.png"
},
"impower":{
type:String,
value:"授权登录"
},
"impower1":{
type:String,
value:"请授权小程序登录"
},
"impower2":{
type:String,
value:"我们不会公布您的这些信息"
},
"impower3":{
type:String,
value:"只是为了给您提供更好的服务"
}
},
/**
* 组件的初始数据
*/
data: {
isShow:true,//这个是判断那个弹出层是否让它出现,默认是显示的
},
//组件与页面相关的生命周期
pageLifetimes:{
//判断进入页面的弹出框是否显示
// show 方法就是 页面被展示
show(){
//拿到的是本地的数据
const token = wx.getStorageSync('token')
console.log(token)
if(token){
this.setData({
isShow:false
})
}else{
console.log(1)
this.setData({
isShow:true
})
}
}
},
/**
* 组件的方法列表
*/
methods: {
//点击允许的执行 方法 给父组件一个方法 相关操作在父组件中执行
getUserinfo(e){
//通过子组件triggerEvent这个方法,把参数传给父组件
this.triggerEvent("allow",e.detail),
//然后更新视图,就是把弹出层关闭
this.setData({
isShow:false
})
},
//这个方法就是父组件调用子组件的方法(在父组件一个点击事件,在子组件中定义一个id,然后this.selectComponent('#tan').getF();拿到子组件中对应的方法)
getF(){
//就是把弹出层显示出来
this.setData({
isShow:true
})
}
},
})
在getUserinfo
这个方法上传一个参数e
。因为现在这个组件是子组件,需要把子组件的值,通过triggerEvent()
这个方法,把参数带到父组件上。
user.js(父组件):就是我的页面
在父组件中使用子组件通过triggerEvent()
这个方法,拿到由子组件传过来的值,如果传过来的值有关于用户信息的,就去到注册页面;如果传过来的值,没有关于用户信息的,就直接弹出一个提示,说明取消登录。
// pages/user/user.js
const AUTH =require("../../utils/register.js")
Page({
/**
* 页面的初始数据
*/
data: {
userInfo:{},//获取的用户的信息
value:"立即"
},
//这个的方法是子组件通过triggerEvent传过来的方法
allow(e){
//通过传参获得的是从组件传过来的页面数
let _this = this //绑定this,为了防止this发生变化
let useinfo = e.detail.userInfo
//如果传过来有内容就是点击了允许 直接去注册登录
if(useinfo){
AUTH.register(_this)
//拿到本地token并保存
AUTH.getuserdetail().then(res=>{
console.log(res)
})
}else{ //否则就是点击了取消 弹出弹框
wx.showToast({
title: '已取消',
})
}
},
layout(){
AUTH.loadingout()
this.onShow()
this.selectComponent('#tan').getF();
},
/**
* 生命周期函数--监听页面加载
*/
//刷新页面是执行
onShow: function () {
//进入我的页面就执行 判断本地存值来让页面显示不同的头像名字
// 先要拿到token
const token = wx.getStorageSync('token')
//如果拿到token,就执行用户详情这个方法,拿到用户的数据,并更新视图
if(token){
AUTH.getuserdetail().then(res=>{
this.setData({
userInfo:res.data.base,
value:"退出"
})
})
}else{//如果没有token就
this.setData({
userInfo:{
avatarUrl:"../../assets/user.png",
nick:"未登录"
}
})
}
}
})
如果传过来的值有关于用户信息的,就去到注册页面。就是通过封装一个方法auth.js文件
,然后把当前的文件引入到父组件的js文件(user.js)中,然后就是通过这个AUTH.register(_this)
去到注册的功能(并把当前父组件的所有内容也带到auth.js
这个文件)
auth.js
我对这个auth.js
这个方法的每一步都表达清楚了。
const { sbq_api } = require("../http/sbq_api/sbq_api.js") //这个就是自己封装的api接口数据
//登陆方法 需要再走一步wx.login,拿到code的方法,返回的code数据如果不等于0,就提示登录失败。登录成功后就拿到token和uid,并保存到本地,之后就是刷新页面
async function login(page) {
//定义this 方便使用
// const _this = this
wx.login({
success: function (res) {
//因为下边登录 一样要用code值 而code值 是一次只能使用一次 所以我们要再次获取code值
let code = res.code
sbq_api("login_wx", { code }).then(function (res) {
if (res.code !== 0) {
wx.showModal({
title: '登陆失败',
})
return;
}
//成功回调后是能够拿到openid和token的 拿到后本地保存
wx.setStorageSync('token', res.data.token)
wx.setStorageSync('uid', res.data.uid)
//登录成功后,就执行父组件的onShow()方法,刷新页面
page.onShow()
})
}
})
}
//注册方法 首先就是要通过wx.login拿到code,通过wx.getUserInfo拿到iv和encryptedData这两个数据
async function register(page) {
//定义当前页面的this 为了方便下文使用
console.log(this)
var _this = this
console.log(_this)
//先进行登录 得到coed值
wx.login({//微信官方的方法拿code
success: function (res) {
//定义code值
let code = res.code
//因为api提供接口上需要code iv 和 encryptedData三个必要参数 所以要获取用户的信息
wx.getUserInfo({//微信官方的方法拿iv 和 encryptedData
success: function (res) {
let encryptedData = res.encryptedData
let iv = res.iv
//三个参数齐全了 就开始调用注册接口,如果拿到的code等于10000,说明你已经注册成功了,就直接去到登录的这个方法
sbq_api("register_complex", { code, encryptedData, iv }).then(function(res) {
//当前用户是否注册
if (res.code === 10000) {
console.log("用户已注册")
//直接走登录
_this.login(page)
return;
}
//刚才已经完成注册直接走登录
_this.login(page)
})
}
})
}
})
}
//查看用户详情
async function getuserdetail(){
return new Promise((resolve,reject)=>{
const token = wx.getStorageSync('token')
//通过api方法获取用户数据
sbq_api("getUserInfo_details",{token}).then(res=>{
resolve(res)
})
})
}
//点击退出登录的按钮
async function loadingout(){
wx.removeStorageSync('token')
wx.removeStorageSync('uid')
}
//抛出所有的方法
module.exports = {
register: register,
login:login,
getuserdetail:getuserdetail,
loadingout:loadingout
}
检查微信服务器登录态是否过期的代码封装:
/**
* Promise封装wx.checkSession(),检查微信服务器登录态是否过期
*/
_checkWXSession() {
return new Promise((resolve, reject) => {
wx.checkSession({
success: () => {
resolve(true)
},
fail: () => {
reject(false)
}
})
})
}