主机参考:VPS测评参考推荐/专注分享VPS服务器优惠信息!若您是商家可以在本站进行投稿,查看详情!此外我们还提供软文收录、PayPal代付、广告赞助等服务,查看详情! |
我们发布的部分优惠活动文章可能存在时效性,购买时建议在本站搜索商家名称可查看相关文章充分了解该商家!若非中文页面可使用Edge浏览器同步翻译!PayPal代付/收录合作 |
今天微信小程序开发专栏介绍小程序登录的前端设计和实现。1.引言如此精心设计登录/注册的目的,当然是为了让这个作为应用的基础能力,足够健壮,避免整个站的阻塞。
同时要充分考虑如何解耦打包,在开发新的小程序时,快速复用能力,避免重复挖掘。
注册这个模块就像冰山一样。我们以为是“输入账号密码,登录”,但还是有各种问题需要考虑。
在这里,我想和大家分享一下最近完成的一个小程序登录/注册模块后沉淀下来的一些设计经验和想法。
二。业务场景在用户浏览小程序的过程中,由于业务需要,往往需要获取用户的一些基本信息。常见的有:
微信手机号昵称不同的微信产品,对用户的信息要求不同,授权流程也不同。
第一种常见于电子商务系统。用户在购买商品时,为了识别用户的多平台账号,往往会用自己的手机号码进行联系。此时,用户需要对自己的手机号码进行授权。
其次,为了得到用户信息的基本初始化,往往需要进一步获取用户信息:如微信昵称、unionId等。,并且需要请求用户授权。
第三类包括第一类和第二类。
3.这个概念旨在解决一套通用的小程序登录方案和服务。我们来分析一下业务,得出变量。
在做技术设计之前,先说一些必要的废话,对一些概念做基本的调频。
2.1关于“注册”注册的英文是“login”,对应的是“logout”。登录前需要有账号,需要「注册」(或者注册)。
一开始产品没有登录/注册功能,后来用的人多了就逐渐有了。对于产品本身的需求,需要找准“用户”。
在现实世界中,我们每个人都有一个身份ID:身份证。16岁那年,我第一次去公安局领身份证的时候,完成了一个“登记”的行为。然后去网吧上网,刷了身份证,完成了一次“登录”行为。
所以对于虚拟世界的互联网来说,这个识别就是“账号+密码”。
常见的登录/注册方法有:
帐户密码注册
在互联网的早期,个人电子邮件和手机的覆盖面很小。所以用户需要自己想一个账号名,我们注册一个QQ号,就是形式。
邮箱地址注册
千禧年之后,PC互联网时代迅速普及,我们都创建了自己的个人邮箱。此外,QQ还配有自己的电子邮件帐户。因为邮箱是私密的,可以交流信息,所以大部分网站都是以邮箱账号作为用户名开始注册的,在注册的过程中会要求登录相应的邮箱查看激活邮箱,验证我们对注册邮箱的所有权。
手机注册
互联网普及后,智能手机和移动互联网发展迅速。手机也成为了每个人必不可少的移动设备,移动互联网已经深深融入了每个人的现代生活。所以,与电子邮件相比,目前手机号码与个人的联系更加紧密,越来越多的移动应用出现。使用移动电话号码作为用户名的注册方法也被广泛使用。
到2020年,微信用户数量将达到12亿。那么,微信账号,至少在中国,已经成为新一代互联网世界的“身份标识”。
对于微信小程序来说,自然可以知道当前用户的微信账号ID。微信允许小程序在用户不知情的情况下“登录”我们的小程序。这就是我们常说的“静默登录”。
其实微信小程序的登录和传统Web应用的“单点登录”是一个概念。
单点登录:可以在a站登录,C站和b站可以实现快速“静默登录”。小程序登录:在微信中,登录微信账号,就可以在整个小程序生态中实现“静默登录”。由于Http最初是无状态的,所以业内对登录状态的一般做法如下:
-Session:常用于浏览器应用访问令牌:常用于移动等非浏览器应用。对于微信小程序来说,“JS逻辑层”并不是一个浏览器环境,所以自然也就没有通常使用的cookie -会话访问令牌。
2.2关于需要用户昵称、手机号码等进一步信息的产品的“授权”。为了微信用户的隐私,需要用户同意授权。这些信息只有小程序应用才能获得,这就导致了目前流行的小程序“授权用户信息”和“授权手机号”的交互。
由于不同用户信息的敏感度不同,微信小程序对不同用户信息提供“授权”的方式也不同:
具体API调用方法,弹出授权。比如调用wx.getLocation()时,如果用户没有被授权,就会弹出地址授权界面。如果拒绝,窗口不会再弹出,wx.getLocation()会直接返回failure。 lt按钮打开-type = ;xxx / gt;方式。只是:用户的敏感信息和用户的手机号码需要和后端对称加密解密才能得到数据。用户拒绝了。再次点击按钮,窗口仍然会弹出。通过wx.authorize(),提前要求授权,之后需要获取相关信息时就不用再弹出授权了。四。详细设计理清概念后,我们的模块可以分为两块:
登录:负责创建与服务器的会话,实现静默登录和相关的容错处理等。该模块命名为会话授权:负责与用户交互、获取和更新信息、控制和处理权限等。该模块被命名为登录3.1.1静默登录的Auth3.1实现
微信提供的官方登录方案总结为三步:
前端通过wx.login()获取一次性加密凭证码,并交给后端。后端代码传输到微信服务器,换取用户的唯一标识符openId和授权证书session_key。(后续服务器和微信服务器的特殊API调用见:微信公文-服务器获取开放数据)。后端将从微信服务器获取的用户凭证和自己生成的登录凭证发送给前端。保存在前端,下次请求时带到后端,这样就可以识别是哪个用户了。如果你只是实现这个过程,那就相当简单了。
但是为了实现健壮的登录过程,需要注意更多的边界条件:
折叠wx.login()的调用:
Wx.login()会产生不可预知的副作用,比如session_key失败,导致后续授权解密场景失败。这里我们可以提供一个类似session.login()的方法,掌握wx.login()的控制,并对其做一系列的封装和容错处理。
通话时间:
我们通常在应用程序启动时启动静默登录(app.onLaunch())。但是会有一个小程序生命周期设计问题导致的异步问题:当加载页面,调用一个需要登录的后端API时,可能无法完成之前的异步静态登录过程,导致请求失败。
当然,也可以在需要登录状态的第一个接口调用时,以异步阻塞的方式发起登录调用,这就需要一个设计良好的接口层。
下面将描述上述两种场景的详细设计思路。
并发调用的问题:
在一个业务场景中,不可避免地会有多个代码需要触发登录。在极端情况下,这些代码会被同时调用。这将导致短时间内多次启动登录过程,即使之前的请求尚未完成。针对这种情况,我们可以阻塞第一次调用,在后续的调用中等待结果,就像精子和卵子结合的过程一样。
尚未过时的问题:
如果我们的登录状态没有过期,可以正常使用,默认不需要发起登录流程。这时候我们可以默认检查登录状态是否可用,然后就可以进行请求了。然后还可以提供一个类似session.login({ force: true})的参数来强制发起登录。
3.1.2静默登录异步状态1的处理。当应用程序启动时调用。
因为大部分情况都是依赖于登录状态的,所以在应用启动的时候我们会很自然的想到这个时候调用(app.onLaunch())。
但由于原生小程序启动过程中App、页面、组件的生命周期钩子函数,不支持异步阻塞。
那么我们就很容易遇到在page.onLoad的时候app.onLaunch发起的“登录过程”还没有完成,无法正确的进行一些依赖于登录状态的操作。
针对这种情况,我们设计了一个状态机的工具:status。
基于状态机,我们可以编写这样的代码:
从 # 39;导入{ Status };@ beauty we/plugin -status # 39;;//on app . jsapp({ Status:{ log in:new Status( # 39;登录 # 39;);},onLaunch() {session //发起静默登录调用。login() //将状态机设置为success . then(()= >;This.status.login.success()) //将状态机设置为fail . catch(()= >;this . status . log in . fail());},});//on page . jspage({ onLoad(){ const loginStatus = getApp(). status . log in;// must会判断状态,比如登录时等待,登录成功时直接返回,登录失败时抛出等。log in status()status . log in . must(()= gt;{//执行一些需要登录状态的操作...});},});复制代码2。当调用“第一个需要登录状态的接口”时,发起登录。
再者,我们会发现,更深层的需要登录状态的节点是在“需要登录状态的后端API”发起的时候。
然后我们可以在调用“需要登录状态的后端API”时发起“静默登录”。对于并发场景,只需让其他请求等待。
以fly.js作为wx.request()封装的“网络请求层”,做一个简单的例子:
//发起请求,并表明请求是fly . post( # 39;https://...',params,{ need log in:true });//处理fly拦截器中的逻辑fly . interceptors . request . use(async(req)= >:{//if(req . need log in!= = false){//ensurelog in的核心逻辑是:确定是否登录,如果没有,发起登录调用,如果正在登录,进入队列等待回调。await session . ensurelog in();//登录成功后,获取令牌,通过headers传递给后端。const token = await session . gettoken();Object.assign(req.headers,{
而session_key是时间敏感的。以下摘自微信官方描述:
会话密钥session_key的有效性开发者如果遇到由于session_key不正确导致的签名验证失败或解密失败,需要注意以下与session_key相关的注意事项。
当调用wx.login时,用户的session_key可能会被更新,旧的session_key会失效(刷新机制的周期最短,如果同一用户在短时间内多次调用wx.login,并不是每次调用都会导致session_key被刷新)。开发者应该在明确需要重新登录的情况下才调用wx.login,并及时通过auth.code2Session接口更新服务器中存储的session_key。微信不会通知开发者session_key的有效期。我们会根据用户使用小程序的行为来更新session_key。用户使用小程序越频繁,session_key的有效期就会越长。当开发人员的session_key失败时,您可以通过重新执行登录过程来获得有效的session_key。接口wx.checkSession可以用来验证session_key是否有效,从而防止小程序重复执行登录过程。开发者实现自定义登录状态时,可以考虑将session_key的有效期作为自己登录状态的有效期,也可以实现自定义的时效性策略。翻译成两个简单的句子:
Session_key时效由微信控制,开发者无法预测。Wx.login可能会导致session_key过期。在使用该接口之前,可以使用wx.checkSession对其进行检查。至于第二点,我们通过实验发现,在session_key已经过期的情况下,wx.checkSession偶尔会在概率上返回true。
还有来自社区的相关反馈尚未解决:
小程序解密手机号码。过了一小段时间,checkSession:ok,但是解密失败。wx.checkSession有效,但解密数据失败。Checksession判断session_key不是无效,而是手机号解密失败,所以结论是wx.checkSession的可靠性没有达到100%。
基于以上,我们需要对session_key的到期做一些容错处理:
在发起需要使用session_key的请求之前,先做一次wx.checkSession。如果失败,刷新登录状态。当后端session_key无法解密打开的数据时,返回特定的错误代码(比如DECRYPT_WX_OPEN_DATA_FAIL),前端刷新登录状态。示例代码:
//定义检查session_key const保证session key = async () = >有效性的操作;{ const has session = wait new Promise(resolve = gt;{ wx . check session({ success:()= gt;resolve(true),fail:()= gt;resolve(false),});});如果(!has session){ logger . info( # 39;SessionKey已过期,刷新登录状态 # 39;);//按照上面提到的刷新登录逻辑返回session . refresh log in();} return promise . resolve();}//发起请求时,做一个操作保证最新的session_key(以fly.js为网络请求层为例)const update phone = async(params)= >;{ await ensureSessionKey();const RES = await fly . post( # 39;https://XXX # 39;,params);}//添加响应拦截器监听网络请求返回fly . interceptors . response . use((response)= >;{ const code = res.data//登录状态过期或失败,如果(
那么授权的阶段可以分为三个级别:
//阶段用户登录导出enum AuthStep {//阶段1:只有登录状态,没有用户信息,没有手机号一= 1,//阶段2:用户信息,没有手机号二= 2,//阶段3:用户信息,手机号三= 3。}复制代码AuthStep的推进过程是不可逆的,我们可以定义一个nextStep函数。外用的话,就无脑调用nextStep方法,等待回调结果。
示例代码:
//Auth-FlowComponent组件({//...数据:{//默认情况下只需要达到阶段二。MustAuthStep: AuthStep。TWO },//允许对组件进行临时更改所需达到的阶段。setMustAuthStep(mustAuthStep:auth step){ this . setdata({ mustAuthStep });},//根据用户当前的信息,计算出用户处于授权阶段getAuthStep(){ let curr authstep;//没有用户信息,还是第一步如果(!session.hasUser() ||!session . hasunionid()){ currAuthStep = AuthStepType。一;}//没有手机号,还在第二步如果(!session . has phone()){ currAuthStep = AuthStepType。二;}//both,而且还在第三步curr auth step = authsteptype . three;返回currAuthStep}//发起下一次授权。如果全部完成,会直接返回成功。next step(e){ const { mustAuthStep } = this . data;const curr authstep = this . updateauthstep();//authorization if(curr authstep >:= mustauthstep | | curr authstep = = authsteptype . three){//更新全局授权状态机,向订阅者广播消息。返回getApp()status . auth . success();}//第一步:更新用户信息if(curr authstep = = authsteptype . one){//已有密文信息,更新用户信息if(e)session . Update user(e);//更新到视图层,显示对应的UI,等待获取用户信息else this . setdata({ curr auth step });返回;}//第二步:更新手机信息if(curr authstep = = authsteptype . two){//已有密文信息,更新手机号if(e)this . bind phone(e);//没有密文信息,弹出采集窗口elsethis . setdata({ curr auth step });返回;} console . warn( # 39;Auth.nextStep错误 # 39;,{ currAuthStep,mustAuthStep });}, // ...});复制代码,然后我们的
示例代码:
ltview class = auth -flow ; gt lt!--授权完成-->; ltblock wx:if = ;{ { curr AuthStep = = = mustAuthStep | | curr AuthStep = = = AuthStep。三} } gt lt视图 gt授权完成; ltblock wx:elif = ;{{currAuthStep === AuthStep。ONE } } gt ltuser -容器绑定:getuserinfo = 下一步 gt lt视图 gt授权用户信息; ltblock wx:elif = ;{{currAuthStep === AuthStep。两个} } gt ltphone -容器绑定:getphonenumber = 下一步 gt lt视图 gt授权手机号码
我们整理出需要授权的场景:
点击一个按钮,例如:购买一件商品。
对于这种场景,通常通过弹出窗口完成授权,用户可以选择关闭它。
浏览页面,例如:访问个人中心。
对于这种场景,我们可以在点击跳转到某个页面的时候拦截弹出。但这样做的缺点是可能会有很多地方跳转到目标页面,每一个都会被拦截,必然会出现错漏。而当目标页面作为“小程序的登陆页面”时,就不可避免了。
这时,我们可以通过重定向到授权页面来完成授权过程,然后再回来。
然后我们定义一个枚举变量:
//授权显示表单导出枚举AuthDisplayMode {//POPUP = # 39;按钮 # 39;,//以页面的形式PAGE = # 39第#39页;,}复制代码我们可以设计一个mustAuth方法,在点击按钮的时候,或者加载页面的时候进行授权控制。
伪代码示例:
类别{//...musthauth({ mustauthstep = authsteptype . two,//需要授权的级别,用户数据popupCompName = # 39默认情况下是必需的;auth -popup # 39;,//id mode = authdisplaymode.popup授权弹出组件,//默认为弹出模式} = { }):Promise lt := mustAuthStep)返回promise . resolve();//尝试获取< auth -popup id = ;auth -popup ;/ gt;component const pages = getCurrentPages();const curPage =页数
登录到静默登录
Entry: code:产生于wx.login () Entry: token: userInfo:用户信息描述:后端使用代码与微信客户端交换用户标识,然后注册登录用户,将自定义的登录令牌返回给前端token,将存储在前端。每个请求都会带来userInfo,它需要包括昵称和电话字段。前端用于计算当前用户的授权阶段。当然这个状态的记录可以放在后端,但是我们觉得放在前端会更灵活。更新用户信息更新用户
Entry: nickname:用户昵称encrypt: IV与微信开放数据IV、encryptedData相关的性别地址等其他不必要的字段。Entry: userInfo:更新的最新用户信息描述:后端解密微信开放数据,获取隐藏数据,如unionId等。后端支持更新包括昵称在内的用户基本信息。前端将userInfo信息更新到用于计算授权阶段的会话。更新用户的手机号码更新电话
Entry: encrypt:微信开放数据相关四、encryptedData Entry: userInfo:更新的最新用户信息描述:后端解密开放的office,获取手机号,更新为用户信息。前端将userInfo信息更新到用于计算授权阶段的会话。解除手机号码绑定。
In: - Out: -描述:后端解绑用户手机号,无论成功与否,都遵循服务定义的前端协议。登录注销
参与人数:3人以上
输出:-
描述:后端主动过期登录状态,无论成功与否,都遵循业务定义的前端协议。
动词 (verb的缩写)架构图最后,我们来梳理一下整体“注册服务”的架构图:
对于“登录服务”和“基础设施”结合提供的通用服务,业务层只需要根据产品需求定制授权流程
不及物动词摘要本文通过一些常见的登录授权场景来描述细节。
梳理了“注册”和“授权”的概念。
然后,介绍了“登录”的一些关键技术:
静默登录静默登录异步状态处理自定义登录状态过期容错处理微信session_key过期容错处理。对于“授权”,会有设计UI部分的逻辑,也需要涉及组件拆分:
组件拆分和设计权限拦截的处理。然后整理了这个登录授权方案所依赖的后端接口,给出了最简单的参考协议。
最后,本文从“为小程序解决一套通用的登录方案和服务”的角度,梳理了层次结构。
以上是微信小程序登录前端设计和实现的详细内容。请多关注主机参考其他相关文章!
这几篇文章你可能也喜欢:
- 了解微信小程序登录的前端设计和实现(微信小程序登录后端)
- 如何实现小程序的登录和授权(微信小程序登录授权流程)
- 如何解决帝国cms后台无法登录的问题(帝国cms移动终端)
- WordPress登录失败?这五个步骤帮你解决!(wordpress登录门户)
- WordPress后台登录难?试试这些有效的方法吧!
本文由主机参考刊发,转载请注明:了解微信小程序登录的前端设计和实现(如何实现小程序登录) https://zhujicankao.com/82081.html
评论前必须登录!
注册