发布日期:2021-01-24 07:59:20浏览次数:1222
免费生成微信小程序
微信小程序登录是一个非常适用的函数。相信大家都对这个功能的实现感兴趣。所以,今天,我就来介绍一下微信小程序登录的发展和实现。有问题请联系客服,客服会为你解答小程序的各种问题。
微信小程序登录流程实现
用户登录是大多数完整应用程序的必要流程,一个简单的用户系统至少需要关注这些方面
安全性(加密)
持久登录状态(类似于cookie)
登录到期处理
确保用户性,避免多个账户
授权做
绑定用户昵称头像等信息
绑定手机号(实名和保密方法)
许多业务需求可以抽象到Restful接口中,以配合CRUD操作
然而,登录过程是复杂的,每个平台都有自己的流程,这已经成为项目中耗时的一部分,比如小程序的登录流程
对于一个从头开始的项目来说,获得登录过程是一个好的开始,一个好的开始,也是成功的一半
基于微信小程序平台,讲述了一个完整的用户自定义登录过程,一起吃这块硬骨头
名词解释
首先,简要说明登录过程时序图中出现的名词
代码临时登录证书,有效期五分钟,通过wx.login()获得
Session_key会话密钥,由服务器通过code2Session获取
这个小程序下openId用户的用户标识永远不会变,服务器会通过代码获取
同一个微信开放平台账户(微信官方账户、小程序、网站、移动应用)下的银联用户标识永远不变
appId小程序的标识
应用程序秘密小程序的应用程序秘密可以与会话密钥的代码和应用程序标识进行交换
其他名词
原始数据不包括用于计算签名的敏感信息的原始数据字符串
加密数据包含敏感的用户信息,并且经过加密
签名用于验证用户信息是否未被篡改
iv加密算法的初始向量
什么信息是敏感的?手机号,openId,unionId,可以看出这些值可以定位一个用户,而不能定位用户的昵称和头像则不是敏感信息
小程序登录相关函数
wx.login
wx.getUserInfo
wx.checkSession
小程序承诺
我们发现小程序的异步接口是成功和失败的回调,所以很容易写回调地狱
因此,我们可以简单地实现一个wx异步函数,先把它变成一个承诺工具函数
const promisify=original={
返回函数(opt) {
返回新承诺((解决,拒绝)={
opt=Object.assign({
成功:解决,
fail:拒绝
},opt)
原始(可选)
})
}
}
所以我们可以这样调用函数
promisify(wx . GetStorage)({ key : ' key ' })。然后(值={
//成功
}).catch(原因={
//失败
})
服务器端实现
这个演示的服务器端实现基于express.js
请注意,为了演示的简单性,服务器使用js变量来保存用户数据,这意味着如果服务器重新启动,用户数据将被清空
如果需要持久存储用户数据,可以自己实现数据库相关的逻辑
//存储所有用户信息
const用户={
//openId作为索引
openId: {
//数据结构如下
OpenId: ' ',//理论上不应该返回前端
会话密钥: ' ',
昵称: ' ',
avatarUrl: ' ',
unionId: ' ',
电话号码: ' '
}
}
应用。使用(bodyParser.json())。使用(会话({
secret: '一个女孩',
resave: false,
saveUninitialized: true
}))
小程序登录
我们首先实现一个基本的oauth授权登录
Oauth授权登录主要是openId和sessionKey交换代码的过程
前端小程序登录
用app.js写的
login () {
Console.log('登录')
return util.promisify(wx.login)()。然后(({code})={
console.log(`code: ${code} `)
返回http.post('/oauth/login ',{
代码,
type: 'wxapp '
})
})
}
服务器实现oauth授权
服务器实现上述接口/oauth/登录
应用。post('/oauth/login ',(req,res)={
var params=req.body
var {code,type}=params
if(type==' wxapp '){
//代码换取信息和会话密钥的主要逻辑
axios。get(' https://API。微信。QQ。' com/SNS/jscode 2 session ',{
params: {
appid: config.appId,
secret: config.appSecret,
js_code:代码,
grant _ type : ' authorization _ code '
}
}).然后(({数据})={
var openId=data.openid
var user=user[OpenID]
if(!用户){
用户={
openId,
会话密钥:数据。会话密钥(_ k)
}
用户[openId]=用户
console.log('新用户,用户)
} else {
console.log('老用户,用户)
}
req.session.openId=user.openId
req.user=用户
}).然后(()={
res.send({
代码: 0
})
})
} else {
引发新错误('未知的授权类型)
}
})
获取用户信息
登录系统中都会有一个重要的功能: 获取用户信息,我们称之为户信息
如果已登录用户调用户信息则返回用户信息,比如昵称,头像等,如果未登录则返回'用户未登录'
也就是说此接口还有判断用户是否登录的功效.
小程序的用户信息一般存储在app.globalData.userInfo中(模板如此)
我们在服务端加上前置中间件,通过会议来获取对应的用户信息,并放在请求对象中
应用。使用((req,res,next)={
请求。用户=用户[请求。会话。OpenID]
下一个()
})
然后实现/user/info接口,用来返回用户信息
应用。get('/user/info ',(req,res)={
if (req.user) {
return res.send({
代码: 0,
data: req.user
})
}
引发新错误('用户未登录)
})
小程序调用用户信息接口
getUserInfo () {
返回http.get('/user/info ').然后(响应={
让数据=响应。数据
if(数据的数据类型==' object '){
//获取用户信息成功则保存到全局
this.globalData.userInfo=数据
返回数据
}
返回承诺。拒绝(回应)
})
}
专为小程序发请求设计的库
小程序代码通过http.get,http.post这样的美国石油学会(美国石油学会)来发请求,背后使用了一个请求库,@chunpu/http1是一个专门为小程序设计的超文本传送协议(超文本传输协议的缩写)请求库,可以在小程序上像爱可信一样发请求,支持拦截器等强大功能,甚至比爱可信更顺手
初始化方法如下
从" @春浦/http "导入超文本传送协议(Hyper Text Transport Protocol的缩写)
http.init({
基本URL : ' http://localhost :9999 ',//定义baseURL,用于本地测试
wx //标记是微信小程序用
})
具体使用方法可参照文档https://github.com/chunpu/http#readme
自定义登录态持久化
浏览器有饼干,然而小程序没有饼干,那怎么模仿出像网页这样的登录态呢?
这里要用到小程序自己的持久化接口,也就是setStorage和getStorage
为了方便各端共用接口,或者直接复用蜘蛛网接口,我们自行实现一个简单的读甜饼干和种甜饼干的逻辑
先是要根依据返回的超文本传送协议(Hyper Text Transport Protocol的缩写)响应头来种上饼干,此处我们用到了@chunpu/http中的反应拦截器,和爱可信用法一样
http。拦截器。回应。使用(响应={
//种甜饼干
var {headers}=响应
var cookies=headers[' set-cookie ']| | ' '
cookie=cookies . split(/,*/).reduce((prev,item)={
项目=项目。split(/;*/)[0]
var obj=http.qs.parse(item)
返回对象。分配(上一个,对象)
}, {})
if (cookies) {
返回util。promisify(wx。GetStorage)({
key: 'cookie '
}).catch(()={})。然后(res={
res=res || {}
var allCookies=res.data || {}
对象。分配(所有无锅饼干)
返回util。promisify(wx。SetStorage()({
key: 'cookie ',
data: allCookies
})
}).然后(()={
返回响应
})
}
返回响应
})
当然我们还需要在发请求的时候带上所有饼干,此处用的是请求拦截器
http。拦截器。请求。使用(配置={
//给请求带上甜饼干
返回util。promisify(wx。GetStorage)({
key: 'cookie '
}).catch(()={})。然后(res={
if(RES . data){
Object.assign(config.headers,{
cookie : http。QS。stringify(RES . data,';', '=')
})
}
返回配置
})
})
登录态的有效期
我们知道,浏览器中的登录cookie是有过期时间的,比如,七天,或者一个月。可能有些朋友会问问题。如果直接使用存储,小程序的登录有效性如何?
小程序帮助我们实现了会话有效期的判断
比cookie聪明,官方文档描述如下
通过wx.login界面获取的用户登录状态具有一定的时效性。用户不使用小程序的时间越长,用户登录状态越有可能失败。相反,如果用户一直在使用小程序,用户登录状态将一直保持有效
换句话说,这个小程序还会帮我们自动更新登录状态,简直就是人工智能cookie,我喜欢
前端怎么操作?代码是用app.js写的
onLaunch:函数(){
util.promisify(wx.checkSession)()。然后(()={
Console.log(“会话生效”)
返回this.getUserInfo()
}).然后(userInfo={
Console.log('登录成功,用户信息)
}).catch(err={
Console.log('自动登录失败,再次登录',错误)
返回this.login()
}).catch(err={
Console.log('手动登录失败',错误)
})
}
需要注意的是,这里的会话不仅仅是前端的登录状态,还有后端的session_key的有效期。如果前端登录状态失败,后端也失败,需要更新session_key。理论上小程序也可以自定义登录到期时间策略,但是这种情况下我们需要考虑开发者的到期时间和小程序接口服务的到期时间,并不是保持统一那么简单。确保每个页面都能获得用户信息。如果我们选择在新的applet项目中构建一个通用的快速启动模板,我们将得到一个可以直接运行的模板。当我们点击代码时,大部分代码都是在处理userInfo。
纸条上写着
由于getUserInfo是一个网络请求,可能会在Page.onLoad之后返回,因此这里添加了回调来防止这种情况。
但是这个模板不科学,所以只考虑了首页需要用户信息的情况。扫码输入的页面也需要用户信息怎么办?还有直接进入跳转的未付费页面活动页面等。
如果每一页都判断用户信息是否加载,那么代码就太冗余了
这时,我们想到了jQuery的ready函数$(function)。只要文档准备好了,我们就可以直接执行函数中的代码。如果文档没有准备好,我们将等到它准备好执行代码。
就是这个想法!我们把小程序的App当成网页的文档
我们的目标是在没有错误的情况下获得用户信息
页面({
数据: {
用户信息:为空
},
onLoad:函数(){
app.ready(()={
this.setData({
user info : app . global data . user info
})
})
}
})
这里我们用min-read 2实现这个功能,代码实现还是用app.js写的
从“最小就绪”导入就绪
常量就绪=就绪()
App({
getUserInfo () {
//作为全局方法获取用户信息
返回http.get('/user/info ')。然后(响应={
让数据=响应。数据
if(data type of data==' object '){
this.globalData.userInfo=数据
//成功获取userInfo的时间是应用准备就绪的时间
ready.open()
返回数据
}
返回承诺。拒绝(回应)
})
},
就绪(func) {
//将函数放入队列中
ready.queue(函数)
}
})
绑定用户信息和手机号码
仅仅得到用户的openId是不够的。openId只能标记用户,连用户的昵称和头像都无法获取。如何获取用户信息并存储在后端数据库中?
我们在服务器上实现这两个接口,绑定用户信息和绑定用户手机号码
应用。post('/user/bindinfo ',(req,res)={
var user=req.user
if(用户){
var {encryptedData,iv}=req.body
var PC=new WxBizDataCrypt(config . AppID,user.sessionKey)
var data=PC . decryptdata(Encrypted data,iv)
对象.分配(用户,数据)
return res.send({
代码: 0
})
}
抛出新错误(“用户未登录”)
})。post('/user/bindphone ',(req,res)={
var user=req.user
if(用户){
var {encryptedData,iv}=req.body
var PC=new WxBizDataCrypt(配置。AppID,user.sessionKey)
var数据=PC。解密数据(加密数据,iv)
对象。分配(用户,数据)
return res.send({
代码: 0
})
}
引发新错误('用户未登录)
})
小程序个人中心页面结构实现如下
wx:if='{{!用户信息。昵称}}"
type='primary '
open-type='getUserInfo '
bindgetuserinfo='bindUserInfo '获取头像昵称
{{userInfo.nickName}}
wx:if='{{!userInfo.phoneNumber}} '
type='primary '
style=' margin-top : 20px;'
open-type='getPhoneNumber '
bindgetphonenumber=' Bindphonenumber '绑定手机号
{{userInfo.phoneNumber}}
小程序中的bindUserInfo和绑定电话号码函数,根据微信最新的策略,这俩操作都需要用户点击按钮统一授权才能触发
bindUserInfo (e) {
var detail=e.detail
if (detail.iv)
http.post('/user/bindinfo ',{
加密数据:细节。加密数据,
iv:详图iv
签名:细节签名
}).然后(()={
返回app.getUserInfo().然后(userInfo={
this.setData({
用户信息:用户信息
})
})
})
}
},
bindPhoneNumber (e) {
var detail=e.detail
if (detail.iv)
http.post('/user/bindphone ',{
加密数据:细节。加密数据,
iv:详图输入阀交互式视讯自变量(Independent Variable)
}).然后(()={
返回app.getUserInfo().然后(userInfo={
this.setData({
用户信息:用户信息
})
})
})
}
}
(免责声明:本网站内容主要网络,不保证有关资料的准确性及可靠性,读者在使用前请进一步核实,并对任何自主决定的行为负责。本网站概不负任何法律责任)