登录涉及的面比较多:触发场景上,各种页面各种交互路径都可能触发登录;交互过程上,既需要用户提供/证明id,也需要后端记录维护,还需要保证安全性;复用场景上,既是通用功能,需要多场景多页面甚至多小程序复用,又是定制功能,需要各场景/页面/小程序区分处理。要做到各种情形下都有良好的交互体验,且健壮、高效、可复用、可扩展、可维护,还是相对比较复杂的。 本文将探讨小程序登录过程中的一些主要需求和问题,以渐进迭代的方式提出并实现一个健壮、高效的登录方案。 顺带一提,es6语法中的async/await、Promise、decorator等特性对于复杂时序处理相当有增益,在本文中也会有所体现。 基础流程如上图所示,基础登录流程为:
该流程主要基于以下考虑:
健壮流程拒绝授权问题 问题: 获取微信用户信息时,会出现一个授权弹窗,需要用户点击“允许”才能正常获取; 若用户点击“拒绝”,不仅当次登录会失败,一定时间内后续登录也会失败,因为短期内再次调用微信用户信息接口时,微信不会再向用户展示授权弹窗,而是直接按失败返回。 这样导致用户只要拒绝过一次,即使后来对小程序感兴趣了愿意授权了,也难以再次操作。 方案: 如上图所示,增加以下流程以处理拒绝授权问题:
这样,用户拒绝授权只会影响本次登录,不至于无法进行下次尝试。 登录态过期问题 问题:
上图截自微信官方文档,从中可以看出:
此外,实践中发现,wx.checkSession平均耗时约需200ms,每次接口调用前都先检查一遍,开销还是蛮大的。 如何既保证接口功能正确有效,又不用每次耗费高额的查询开销,成为了一个问题。
方案: 如上图所示,增加以下流程以处理登录态过期问题:
这样,只有在真正需要重新登录的时候(无前端登录态/后端登录态失效/后端被提示微信登录态失效)才会重新执行登录流程;并且,一旦需要重新登录,就会自动重新触发登录流程。 并发问题 问题: 如上图所示,页面各组件各功能有可能同时触发登录流程,可能会导致:
方案: 如上图所示,加入免并发逻辑:若登录流程正在进行,则不重复触发登录流程,而是加入当前流程的监听队列,待登录结束时再一并处理。这样,任一时刻最多只有一个登录流程正在进行。 流程实现时序控制 如上图所示,目前登录流程已较为复杂,步骤较多,且大多是异步操作,每步成功失败需要区分处理,处理过程又会相互交织。如果直接在微信接口/网络接口提供的success/fail回调中进行逻辑处理,会造成:
因而采用Promise+async/await进行时序管理: 将每个步骤Promise化: 使用async/await管理整体时序: 如以上代码所示,微信登录、获取微信用户信息、提示授权、打开权限面板等每一步都是异步操作,都要等待success/fail回调才能获得操作结果并发起下一个操作;但利用Promise+async/await,可以像普通流程一样,将这些操作线性组合,顺序处理。 这样,就可以实现直观清晰的时序管理了。 过期处理 如以上代码所示,单独封装一个requestWithLogin函数,在数据请求前后加入登录态处理逻辑,可以保证数据请求会在有后端登录态时被发送/重新发送。 并且,重新登录过程对数据接口调用方是完全透明的,调用方只需要知道自己的接口需不需要登录态,而无需进行任何登录态相关判断处理,重登录过程也不会对接口调用返回结果造成任何影响。 这样,就可以实现登录态过期自动重新登录了。 并发控制 如以上代码所示,利用Promise可以被多次then/catch的特性(亦即,一个async函数调用结果可以被await多次),可以使用一个Promise来记录当前登录流程,后续调用直接对该Promise进行监听。 这样,就可以实现登录流程免并发了。 至此,我们就得到了一个功能可用、相对健壮、相对高效的登录模块。但依然还是存在优化空间的。 场景优化二次授权问题 问题: 用户同意授权后,小程序可以访问到微信用户信息,并且一段时间内再次访问时,也不会重新出现授权弹窗; 但是,如果用户长时间未使用小程序,或将小程序删除重进,则登录时会再次出现授权弹窗。 一方面会对用户造成干扰,影响其浏览效率;另一方面,不利于流失用户召回。 方案: 再次授权场景其实并不是很必要:
因而,增加以下流程以优化二次授权场景: 如上图所示,在微信登录接口调用成功之后,先尝试直接根据openid完成登录过程,若失败再去请求用户授权。 这样,只有新用户才会出现授权弹窗;老用户、回归用户,都可以直接静默完成登录过程。 场景适配问题 问题: 不同场景对登录行为可能有不同的期望:
单一的登录流程很难满足这种多元的场景需求。 方案: 调用登录/要求登录的数据接口时支持指定场景模式: 如上图所示,登录流程支持指定不同场景模式:
实现 场景优化方案主要是增加了一些流程&判断,使用上文中的“时序控制”基本可以解决。 主要难点在于,上文中的免并发机制不再适用。比如,静默模式正在进行时又触发了一个强制模式的请求,此时,应触发授权弹窗正常登录而不是监听使用静默模式的登录结果。 如果拆成每个模式各自免并发,一方面,登录流程需重复书写,不便复用;另一方面,模式之间并发也存在风险。 因而,引入公共步骤并合机制: 如以上代码所示,将登录免并发改为每个公共步骤免并发,登录流程中就可以根据场景模式自由地进行步骤管理。 这样,就可以实现对不同登录场景进行定制化支持。 效果示例 简洁起见,以下代码使用wepy框架写法,原生小程序/其它框架可类似参考。 如以上代码所示,可以做到老用户/回归用户进入页面时自动悄悄登录,以提供更多个性化服务;新用户进入页面时不进行任何干扰,直到进行留言等操作时才自动出现授权弹窗,且授权完成后自动完成该次行为,无需用户再次操作。 并且,这些过程对业务代码是完全透明的,业务代码只需要知道自己调用的接口是 必须登录/最好登录/必须第一次调用就登录/不用登录,并相应地指定 mode=common/silent/force/不使用requestWithLogin,即可。 这样,我们的登录模块可以在不同场景指定不同登录逻辑,从而支持设计实现更多元更精细更流畅的登录交互。 界面优化 问题: 获取微信用户信息时,直接出现系统授权弹窗有时候是很突兀的;使用自定义授权界面和价值文案进行引导,得当的话可以有效提高授权成功率。 而且,从10月10号起,小程序将不再支持自动弹窗授权用户信息和自动打开权限面板,这两种操作必须使用<button>组件由用户主动触发。彼时起,自定义界面将不再是优化,而会是必需。 这意味着登录过程必须与页面dom耦合,之前的纯js逻辑不再适用。 方案1:登录浮层 在所有页面放置登录浮层,页面需要登录时则调起该浮层,经由浮层按钮完成授权及后续流程。 实现
授权浮层AuthModal.wpy: 登录模块login.js: 如以上代码所示,虽然自定义浮层需要展示按钮、等待用户点击、处理点击、考虑用户不点击直接返回,交互流程相对复杂,但依然可以利用Promise使交互细节对外透明。打开浮层时返回一个Promise,在各个交互出口对Promise进行resolve,则使用时只需将其作为一个普通的异步过程对待。 这样,就可以实现无缝接入自定义浮层授权。 方案2:独立登录页 需要授权用户信息时,跳转至一个专门的登录页面,页面中展示引导内容和授权<button>,用户操作完毕后再自动返回先前页面。 实现
授权全局数据模块userAuthHub.js: 登录模块login.js: 登录页login.wpy: 如以上代码所示,虽然授权过程需要进行跨页面交互,但利用Promise和小程序代码包特性,可以在前一页面设置监听,登录页面进行回调。登录页面交互结束后,前一页面会自动继续执行登录流程,调用方无需进行返回刷新等额外处理,数据接口也会继续调用,用户无需再次操作。 这样,就可以实现无缝接入跨页面授权交互。 两种方案都可以实现自定义授权界面。内嵌浮层会增加一定维护成本和少量资源开销,但可以直接在当前页面完成登录交互,页面自定义空间也相对更大;独立登录页会来回跳转牺牲一定的交互体验,但可以把登录所需dom元素集中在登录页,减少维护成本和页面侵入。二者各有优劣,可以按需采用或混合使用。 这样,我们的登录模块可以使用自定义授权界面,从而支持设计实现更雅观更精致的授权引导。 复用优化多小程序间复用&定制 问题: 开发方可能同时维护着多个小程序,这些小程序使用着相同的后端接口和后端用户体系,又有着各自的小程序标识和使用诉求。 一方面,希望登录模块可以统一维护,不需要每个小程序各自开发;另一方面,又希望各小程序可以进行差异化定制,包括小程序前端标识不一致等刚性差异,和授权提示文案、埋点、授权交互等个性差异。 方案&实现: 1、统一流程+个性化配置 2、公共&默认流程由登录模块统一维护,各小程序直接复用;差异流程支持各小程序以配置的形式自定义扩展&覆盖。 3、配置检查 引入配置过程会存在一个潜在风险:触发登录时,小程序尚未完成登录模块配置。 理论上,只要全局都使用同一个登录实例并在app.js顶部进行配置,应该就没有这样的时序风险。但复用方是不会自觉的,不一定会使用同一个实例,配置过程也不一定会被放在顶部,甚至有可能被放在某些异步数据返回之后。因而登录模块只导出唯一实例并加入配置检查环节以保证该逻辑健壮性: 这样,就可以实现在多个小程序间复用登录模块,由登录模块统一维护整体时序和默认流程,同时支持各小程序进行差异性定制&扩展。 多页面间复用&定制 问题: 不同页面对登录过程有时也存在定制需求,比如授权引导文案,有些页面可能希望提示“授权后可以免费领红包”,有些页面可能是“授权后可以为好友助力”/“授权后可以获得智能推荐”/... 诸如此类。 方案&实现: 在页面中设置钩子供其提供个性化配置。 页面xxx.wpy: 小程序级登录配置: 这样,就可以实现所有页面共用登录模块的同时,支持每个页面进行定制化修改。 这样,我们的登录模块可以在多小程序、多页面中复用,并支持各小程序、各页面进行差异性定制。从而实现更好的可维护性可扩展性:
总结
|
|