登录模块基础知识
用户登录是微信小程序必不可少的环节,一个完整的登录功能还包括用户的信息获取、登录的状态判定等。下图为未登录和已登录页面效果图。
比如下图是未登录状态
登陆后会显示详情信息
前导知识:
小程序通过微信官方提供的,获取微信提登录能力供的用户身份标识,建立用户体系。
用户登录流程时序图(下图所示):
用户登录流程需要小程序、开发者服务器和微信接口服务3个角色的参与,
下面介绍这3个角色的作用:
- 小程序:用户使用的客户端,由于小程序运行在微信之上,因此小程序可以通过API获取微信用户的身份信息。
- 开发者服务器:小程序的后端服务器,用于为小程序用户提供服务。
- 微信接口服务:微信为开发者服务器提供的接口。
这三者通力合作才能完成上述图中过程
登录流程具体细节:
- 小程序获取code。
- 小程序将code发送给开发者服务器。
- 开发者服务器通过微信接口服务校验登录凭证。
- 开发者服务器自定义登录态。
另外还要用到 小程序数据缓存机制,可以参考另一篇博客:
https://yangyongli.blog.csdn.net/article/details/115388965
服务器搭建
由于这次的服务器代码比较多,我放到了另一篇博客中:登录功能服务器搭建 ←←点击查看查看
客户端搭建
在小程序启动时自动执行登录操作。
app.js
login: function() { wx.login({ url: 'http://127.0.0.1:3000/login', method: 'post', data: { code: res.code }, success: res => { console.log('token: ' + res.data.token) // 将token保存为公共数据(用于在多页面中访问) this.globalData.token = res.data.token // 将token保存到数据缓存(下次打开小程序无需重新获取token) wx.setStorage({ key: 'token', data: res.data.token }) } success: res => { console.log('login code: ' + res.code) wx.request({ // 请求login登录接口 }) } }) },
小程序控制台打印
服务器控制台打印出login code和session的值。
token注意事项
判断数据缓存中是否存在token如果存在,取出数据缓存中的token值,不用再执行登录操作。需要注意的是,token有可能会过期,需要重新登录,这就需要从数据缓存中取出token后,先验证token是否过期,再使用token。
检查函数
进入app.js中编写checkLogin()函数,判断token是否存在。
checkLogin: function(callback) { var token = this.globalData.token if (!token) { token = wx.getStorageSync('token') // 从数据缓存中获取token if (token) { this.globalData.token = token; wx.request({ url: 'http://127.0.0.1:3000/checklogin', data: { token: token }, success: res => { callback({ is_login: res.data.is_login }) } }) } else { callback({ is_login: false }) return }} // 如果token存在,请求服务器,判断是否有效 }
修改app.js中onLaunch()函数,用于在小程序启动后检查用户是否已经登录,如果没有登录则执行登录操作。
onLaunch: function() { this.checkLogin(res => { console.log('is_login: ', res.is_login) if (!res.is_login) { this.login() } }) }
获取用户信息
获取用户信息的两种常用方式如下:
1.使用组件来获取
特点:不需要用户授权,可以直接显示用户的头像、昵称、性别等,适合只用来展示信息的情况。
// 示例代码: <!-- 用户头像 --> <open-data type="userAvatarUrl"></open-data> <!-- 用户昵称 --> <open-data type="userNickName"></open-data> <!-- 用户性别 --> <open-data type="userGender" lang="zh_CN"></open-data>
2.单击按钮提示授权的方式
用法:如果“!hasUserInfo”值为true,表示没有获取到用户信息,显示“获取头像昵称”按钮;如果值为false,则将用户信息显示在页面中。
<button wx:if="{{!hasUserInfo}}" open-type="getUserInfo" bindgetuserinfo="getUserInfo"> 获取头像昵称 </button>
js中getUserInfo函数
data: { userInfo: {}, hasUserInfo: false }, getUserInfo: function(e) { if (e.detail.userInfo) { this.setData({ userInfo: e.detail.userInfo, hasUserInfo: true }) } }
判断之前是否授权
在app.js文件的onLaunch()函数中,编写如下代码,在下次启动时判断是否已经授权。
wx.getSetting({ success: res => { if (res.authSetting['scope.userInfo']) { wx.getUserInfo({ // 表示用户已经授权,可以直接获取到用户信息 success: res => { this.globalData.userInfo = res.userInfo } // 将res.userInfo保存到公共数据中,以便在其他页面可以调用 }) } } })
用法:在app.js文件的globalData中增加userInfo,编写如下代码。
globalData: { userInfo: null, // 增加代码 token: null }
调用:在其他页面通过app.globalData.userInf获取到用户信息。
案例:用户登录
wxml
<!--pages/index/index.wxml--> <button bindtap="credit">获取用户的积分</button> <!-- 用户头像 --> <open-data type="userAvatarUrl"></open-data> <!-- 用户昵称 --> <open-data type="userNickName"></open-data> <!-- 用户性别 --> <open-data type="userGender" lang="zh_CN"></open-data> <!-- 单击按钮提示授权 --> <view class="container"> <view class="userinfo"> <button wx:if="{{!hasUserInfo}}" open-type="getUserInfo" bindgetuserinfo="getUserInfo"> 获取头像昵称 </button> <block wx:else> <!-- 用户头像 --> <image class="userinfo-avatar" src="{{userInfo.avatarUrl}}" mode="cover"></image> <!-- 用户昵称 --> <text class="userinfo-nickname">{{userInfo.nickName}}</text> <!-- 用户所在城市 --> <text class="userinfo-nickname">{{userInfo.city}}</text> <!-- 用户性别 --> <open-data type="userGender" lang="zh_CN"></open-data> </block> </view> </view> <!-- 开放数据加密与解密 --> <button bindtap="sendUserInfo">将用户信息发给服务器</button>
js
const app = getApp() Page({ data: { userInfo: {}, hasUserInfo: false }, credit: function () { wx.request({ url: 'http://127.0.0.1:3000/credit', data: { token: app.globalData.token }, success: res => { console.log(res.data) } }) }, getUserInfo: function (e) { console.log("getUserInfo函数"); console.log(e.detail.userInfo) if (e.detail.userInfo) { this.setData({ userInfo: e.detail.userInfo, hasUserInfo: true }) } }, onLoad: function () { console.log("onLoad函数"); if (app.globalData.userInfo) { this.setData({ userInfo: app.globalData.userInfo, hasUserInfo: true }) } else { app.userInfoReadyCallback = res => { this.setData({ userInfo: res.userInfo, hasUserInfo: true }) } } }, sendUserInfo: function () { console.log("sendUserInfo函数"); var token = app.globalData.token wx.getUserInfo({ success: res => { wx.request({ url: 'http://127.0.0.1:3000/userinfo?token=' + token, method: 'post', data: { rawData: res.rawData, signature: res.signature, encryptedData: res.encryptedData, iv: res.iv } }) } }) } })