微信小程序登录方案_第1页
微信小程序登录方案_第2页
微信小程序登录方案_第3页
微信小程序登录方案_第4页
微信小程序登录方案_第5页
已阅读5页,还剩11页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

微信⼩程序登录⽅案登录是⼀项核⼼基础功能,通过登录对⽤户进⾏唯⼀标识,继⽽才可以提供各种跟踪服务,如收藏、下单、留⾔、消息、发布、个性化推荐等。⼩程序功能的⽅⽅⾯⾯⼤多会直接/间接涉及登录,因⽽,登录功能健壮与否⾼效与否是值得重点关注与保障的。登录涉及的⾯⽐较多:触发场景上,各种页⾯各种交互路径都可能触发登录;交互过程上,既需要⽤户提供/证明id,也需要后端记录维护,还需要保证安全性;复⽤场景上,既是通⽤功能,需要多场景多页⾯甚⾄多⼩程序复⽤,⼜是定制功能,需要各场景/页⾯/⼩程序区分处理。要做到各种情形下都有良好的交互体验,且健壮、⾼效、可复⽤、可扩展、可维护,还是相对⽐较复杂的。本⽂将探讨⼩程序登录过程中的⼀些主要需求和问题,以渐进迭代的⽅式提出并实现⼀个健壮、⾼效的登录⽅案。顺带⼀提,es6语法中的async/await、Promise、decorator等特性对于复杂时序处理相当有增益,在本⽂中也会有所体现。基础流程如上图所⽰,基础登录流程为:调⽤微信登录接⼝wx.login获取微信登录态调⽤微信⽤户信息接⼝wx.getUserInfo获取微信⽤户信息调⽤后端登录接⼝,根据微信⽤户标识及信息,记录维护⾃⼰的⽤户体系该流程主要基于以下考虑:交互上,⽤户只需在微信的授权弹窗上点击确认,不需要输⼊账号密码等复杂操作;体验上,可以直接获取微信昵称头像等作为初始⽤户信息,使⽤起来更亲切,传播时好友辨识度也更⾼;开发上,可以直接使⽤或映射微信⽤户标识,⽆需⾃⼰进⾏标识的⽣成和验证;安全上,微信已经在⽤户信息的获取、传输、解密等环节做了许多处理,安全性相对有保障。健壮流程拒绝授权问题问题:获取微信⽤户信息时,会出现⼀个授权弹窗,需要⽤户点击“允许”才能正常获取;若⽤户点击“拒绝”,不仅当次登录会失败,⼀定时间内后续登录也会失败,因为短期内再次调⽤微信⽤户信息接⼝时,微信不会再向⽤户展⽰授权弹窗,⽽是直接按失败返回。这样导致⽤户只要拒绝过⼀次,即使后来对⼩程序感兴趣了愿意授权了,也难以再次操作。⽅案:如上图所⽰,增加以下流程以处理拒绝授权问题:获取微信⽤户信息失败时,判断是否近期内拒绝授权导致;若为拒绝授权导致,则提⽰并打开权限⾯板,供⽤户再次操作;若⽤户依然未授权,则本次登录失败,否则继续后续流程。这样,⽤户拒绝授权只会影响本次登录,不⾄于⽆法进⾏下次尝试。登录态过期问题问题:微信登录态有效期不可控上图截⾃微信官⽅⽂档,从中可以看出:后端session_key随时可能失效,什么时候失效开发者不可控;要保证调⽤接⼝时后端session_key不失效,只能在每次调⽤前先使⽤wx.checkSession检查有效期或直接重新执⾏微信登录接⼝;前端不能随便重新执⾏微信登录接⼝,可能导致正在进⾏的其它后端任务session_key失效;此外,实践中发现,wx.checkSession平均耗时约需200ms,每次接⼝调⽤前都先检查⼀遍,开销还是蛮⼤的。如何既保证接⼝功能正确有效,⼜不⽤每次耗费⾼额的查询开销,成为了⼀个问题。后端登录态过期后端⾃⾝的登录态有效期也存在类似的问题,有可能在调⽤接⼝时才发现后端登录态已过期。⽅案:如上图所⽰,增加以下流程以处理登录态过期问题:调⽤数据接⼝时显式指明是否需要登录态,若需要则在接⼝调⽤前后⾃动加⼊登录态校验逻辑;接⼝调⽤前只校验前端登录态,不校验后端登录态,也不校验微信登录态,以节省每次校验开销;接⼝调⽤后校验后端及微信登录态,若后端返回登录态相关错误码,则重置前端登录态、重新登录、重新调⽤数据接⼝。这样,只有在真正需要重新登录的时候(⽆前端登录态/后端登录态失效/后端被提⽰微信登录态失效)才会重新执⾏登录流程;并且,⼀旦需要重新登录,就会⾃动重新触发登录流程。并发问题问题:如上图所⽰,页⾯各组件各功能有可能同时触发登录流程,可能会导致:额外性能开销,登录流程重复进⾏,登录接⼝重复调⽤;体验问题,连续多次弹窗,影响⽤户交互;逻辑问题,后⼀次登录刷新了前⼀次登录的session_key,导致前⼀次登录接⼝解码失败,返回异常结果。⽅案:如上图所⽰,加⼊免并发逻辑:若登录流程正在进⾏,则不重复触发登录流程,⽽是加⼊当前流程的监听队列,待登录结束时再⼀并处理。这样,任⼀时刻最多只有⼀个登录流程正在进⾏。流程实现时序控制如上图所⽰,⽬前登录流程已较为复杂,步骤较多,且⼤多是异步操作,每步成功失败需要区分处理,处理过程⼜会相互交织。如果直接在微信接⼝/⽹络接⼝提供的success/fail回调中进⾏逻辑处理,会造成:回调层层嵌套,影响代码书写和阅读;不同路径公共步骤难以统⼀提取;时序逻辑不直观,不易管理。因⽽⽤Promise+async/await进⾏时序管理:将每个步骤Promise化:classLogin{static_loginSteps={//各登录步骤/***微信登录:调⽤微信相关API,获取⽤户标识(openid,某些情况下也能获得unionid)*@return{Promise<Object>}微信⽤户标识*/wxLogin(){returnnewPromise((resolve,reject)=>{//结果以Promise形式返回wx.login({success(res){resolve(Object.assign(res,{succeeded:true}));//成功失败都resolve,并通过succeeded字段区分},fail(res){resolve(Object.assign(res,{succeeded:false}));//成功失败都resolve,并通过succeeded字段区分},})});},/***获取微信⽤户信息:调⽤微信相关API,请求⽤户授权访问个⼈信息*@return{Promise<Object>}微信⽤户信息*/requestUserInfo(){returnnewPromise((resolve,reject)=>{//结果以Promise形式返回//...});},//...}}使⽤async/await管理整体时序:classLogin{staticasync_login(){//管理整体时序//letsteps=Login._loginSteps;//微信登录letwxLoginRes=awaitsteps.wxLogin();if(!wxLoginRes.succeeded)//微信登录接⼝异常,登录失败return{code:-1};//获取微信⽤户信息letuserInfoRes=awaitsteps.requestUserInfo();if(!userInfoRes.succeeded&&userInfoRes.failType==='userDeny'){//⽤户近期内曾经拒绝授权导致获取信息失败awaitsteps.tipAuth();//提⽰授权letsettingRes=awaitsteps.openSetting();//打开权限⾯板if(!settingRes.succeeded)//⽤户依然拒绝授权,登录失败return{code:-2};userInfoRes=awaitsteps.requestUserInfo();//⽤户同意授权,重新获取⽤户信息}if(!userInfoRes.succeeded)//其它原因导致的获取⽤户信息失败return{code:-3};//获取⽤户信息成功,进⾏后续流程//}}如以上代码所⽰,微信登录、获取微信⽤户信息、提⽰授权、打开权限⾯板等每⼀步都是异步操作,都要等待success/fail回调才能获得操作结果并发起下⼀个操作;但利⽤Promise+async/await,可以像普通流程⼀样,将这些操作线性组合,顺序处理。这样,就可以实现直观清晰的时序管理了。过期处理classLogin{/***登录*/staticasynclogin(options){if(Login.checkLogin())//若已有前端登录态,则直接按登录成功返回return{code:0};//否则执⾏登录流程//...}/***普通数据请求,不进⾏登录态检查,结果以Promise形式返回*@param{Object}options参数,格式同wx.request*@return{Promise}请求结果,resolve时为数据接⼝返回内容,reject时为请求详情*/staticasyncrequest(options){returnnewPromise((resolve,reject)=>{wx.request(Object.assign({},options,{success(res){resolve(res.data);},fail(res){reject(res);}});});}/***要求登录态的数据请求,封装了登录态逻辑*@param{Object}options请求参数,格式同wx.request*@param{Object}options.loginOpts登录选项,格式同login函数*@return{Promise}返回结果,resolve时为数据接⼝返回内容,reject时为请求详情*/staticasyncrequestWithLogin(options){//先校验/获取前端登录态,保证⼤部分情况下请求发出时已登录letloginRes=awaitLogin.login(options.loginOpts);if(loginRes.code!=0)thrownewError('loginfailed,requestnotsent:'+options.url);//发送数据请求letresp=awaitLogin.request(options);//若后端登录态正常,则正常返回数据请求结果if(!Login._config.apiAuthFail(resp,options))//根据后端统⼀错误码判断登录态是否过期returnresp;//若后端登录态过期Login._clearLoginInfo();//重置前端登录态,保证后续再次调⽤login时会真正执⾏登录环节returnLogin.requestWithLogin(options);//重新登录,重新发送请求,并将重新发送的请求的返回结果作为本次调⽤结果予以返回}}如以上代码所⽰,单独封装⼀个requestWithLogin函数,在数据请求前后加⼊登录态处理逻辑,可以保证数据请求会在有后端登录态时被发送/重新发送。并且,重新登录过程对数据接⼝调⽤⽅是完全透明的,调⽤⽅只需要知道⾃⼰的接⼝需不需要登录态,⽽⽆需进⾏任何登录态相关判断处理,重登录过程也不会对接⼝调⽤返回结果造成任何影响。这样,就可以实现登录态过期⾃动重新登录了。并发控制classLogin{static_loginSingleton=null;//正在进⾏的登录流程staticasync_login(){//登录流程...}//封装了免并发逻辑的登录函数staticasynclogin(){if(Login._loginSingleton)//若当前有登录流程正在进⾏,则直接使⽤其结果作为本次登录结果returnLogin._loginSingleton;//否则触发登录流程Login._loginSingleton=Login._login();//并在登录结束时释放并发限制Login._loginSingleton.then(()=>{Login._loginSingleton=null}).catch(()=>{Login._loginSingleton=null});//返回登录结果returnLogin._loginSingleton;}}如以上代码所⽰,利⽤Promise可以被多次then/catch的特性(亦即,⼀个async函数调⽤结果可以被await多次),可以使⽤⼀个Promise来记录当前登录流程,后续调⽤直接对该Promise进⾏监听。这样,就可以实现登录流程免并发了。⾄此,我们就得到了⼀个功能可⽤、相对健壮、相对⾼效的登录模块。但依然还是存在优化空间的。场景优化⼆次授权问题问题:⽤户同意授权后,⼩程序可以访问到微信⽤户信息,并且⼀段时间内再次访问时,也不会重新出现授权弹窗;但是,如果⽤户长时间未使⽤⼩程序,或将⼩程序删除重进,则登录时会再次出现授权弹窗。⼀⽅⾯会对⽤户造成⼲扰,影响其浏览效率;另⼀⽅⾯,不利于流失⽤户召回。⽅案:再次授权场景其实并不是很必要:⽤户第⼀次授权时,开发者已经可以获得⽤户昵称、头像等⽤户信息和openid、unionid等⽤户标识;再次授权时,虽然⽤户信息可能有更新,但完全可以等⽤户进个⼈主页/编辑信息时再进⾏同步,没必要刚进⼩程序就弹窗;再次授权时,⽤户标识并不会变化;只调⽤微信登录接⼝,不触发授权,已经可以获得openid了,通过openid就可以从数据库中查找使⽤其上次授权时的⽤户信息和unionid等其它⽤户标识。因⽽,增加以下流程以优化⼆次授权场景:如上图所⽰,在微信登录接⼝调⽤成功之后,先尝试直接根据openid完成登录过程,若失败再去请求⽤户授权。这样,只有新⽤户才会出现授权弹窗;⽼⽤户、回归⽤户,都可以直接静默完成登录过程。场景适配问题问题:不同场景对登录⾏为可能有不同的期望:有些场景,希望只在需要时⾃动登录,如商品详情页,希望在⽤户点击留⾔、收藏等按钮时⾃动调起登录并完成留⾔、收藏等相应操作;有些场景,希望只尝试静默登录,如⾸页,希望对⽤户做个性化推荐和针对性投放,但⼜不愿弹窗阻挠⽤户;有些场景,希望保证前后端登录态⼀致,如微信接⼝数据解码。单⼀的登录流程很难满⾜这种多元的场景需求。⽅案:调⽤登录/要求登录的数据接⼝时⽀持指定场景模式:如上图所⽰,登录流程⽀持指定不同场景模式:通⽤模式,为默认模式,会⾃动调起登录并完成相应数据请求和后续操作;静默模式,只会尝试静默登录,不会尝试授权登录,成功与否均不影响页⾯功能和后续接⼝调⽤;强制模式,会重新登录,不管前端是否保有登录态,以保证前后端登录态同步。实现场景优化⽅案主要是增加了⼀些流程&判断,使⽤上⽂中的“时序控制”基本可以解决。主要难点在于,上⽂中的免并发机制不再适⽤。⽐如,静默模式正在进⾏时⼜触发了⼀个强制模式的请求,此时,应触发授权弹窗正常登录⽽不是监听使⽤静默模式的登录结果。如果拆成每个模式各⾃免并发,⼀⽅⾯,登录流程需重复书写,不便复⽤;另⼀⽅⾯,模式之间并发也存在风险。因⽽,引⼊公共步骤并合机制:/***步骤并合修饰器,避免公共步骤并发进⾏*将公共步骤单例化:若步骤未在进⾏,则发起该步骤;若步骤正在进⾏,则监听并使⽤其执⾏结果,⽽不是重新发起该步骤*/functionmergingStep(target,name,descriptor){letoriFunc=descriptor.value;letrunningInstance=null;descriptor.value=function(...args){if(runningInstance)//若步骤正在进⾏,则监听并使⽤其执⾏结果,⽽不是重新发起该步骤returnrunningInstance;letres=oriFunc.apply(this,args);if(!(resinstanceofPromise))returnres;runningInstance=res;runningInstance.then(function(){runningInstance=null;}).catch(function(){runningInstance=null;});returnrunningInstance;}}classLogin{static_loginSteps={@mergingStep//步骤并合修饰器,避免公共步骤并发重复进⾏wxLogin(){returnnewPromise((resolve,reject)=>{//...});},@mergingStep//步骤并合修饰器,避免公共步骤并发重复进⾏asyncsilentLogin({wxLoginRes}){//...},...}staticasynclogin(options){////尝试静默登录letsilentRes=awaitsteps.silentLogin({wxLoginRes});if(silentRes.succeeded){//静默登录成功,结束return{code:0,errMsg:'ok'};}if(options.mode==='silent')//静默模式,只尝试静默登录,不触发授权弹窗;不管成功失败都不影响页⾯功能和后续接⼝调⽤return{code:0,errMsg:'loginfailedsilently'};//其它模式继续尝试授权登录//...}}如以上代码所⽰,将登录免并发改为每个公共步骤免并发,登录流程中就可以根据场景模式⾃由地进⾏步骤管理。这样,就可以实现对不同登录场景进⾏定制化⽀持。效果⽰例简洁起见,以下代码使⽤wepy框架写法,原⽣⼩程序/其它框架可类似参考。importLoginfrom'../../lib/Login';exportdefaultclassextendswepy.page{asynconLoad(){//页⾯初始化letdataRes=awaitLogin.requestWithLogin({//调⽤页⾯数据接⼝url:'xxx/xxx',loginOpts:{mode:'silent'}//使⽤静默模式,若为⽼⽤户/回归⽤户,会⾃动悄悄登录,后端返回数据时可以包含⼀些个性化推荐;若为新⽤户,也不会触发弹窗,});//...}methods={asynconComment(){//⽤户点击了评论按钮letaddRes=awaitLogin.requestWithLogin({//调⽤添加评论接⼝url:'xxx/addComment',data:{comment:'xxx'},loginOpts:{mode:'common'}//使⽤通⽤模式,若已登录,会直接发送请求;若未登录,会⾃动调起登录并发送请求});//...}}}如以上代码所⽰,可以做到⽼⽤户/回归⽤户进⼊页⾯时⾃动悄悄登录,以提供更多个性化服务;新⽤户进⼊页⾯时不进⾏任何⼲扰,直到进⾏留⾔等操作时才⾃动出现授权弹窗,且授权完成后⾃动完成该次⾏为,⽆需⽤户再次操作。并且,这些过程对业务代码是完全透明的,业务代码只需要知道⾃⼰调⽤的接⼝是必须登录/最好登录/必须第⼀次调⽤就登录/不⽤登录,并相应地指定mode=common/silent/force/不使⽤requestWithLogin,即可。这样,我们的登录模块可以在不同场景指定不同登录逻辑,从⽽⽀持设计实现更多元更精细更流畅的登录交互。界⾯优化问题:获取微信⽤户信息时,直接出现系统授权弹窗有时候是很突兀的;使⽤⾃定义授权界⾯和价值⽂案进⾏引导,得当的话可以有效提⾼授权成功率。⽽且,从10⽉10号起,⼩程序将不再⽀持⾃动弹窗授权⽤户信息和⾃动打开权限⾯板,这两种操作必须使⽤<button>组件由⽤户主动触发。彼时起,⾃定义界⾯将不再是优化,⽽会是必需。这意味着登录过程必须与页⾯dom耦合,之前的纯js逻辑不再适⽤。⽅案1:登录浮层在所有页⾯放置登录浮层,页⾯需要登录时则调起该浮层,经由浮层按钮完成授权及后续流程。实现浮层引⼊各个页⾯都需要存在登录浮层。可以将各种页⾯公共dom元素,包括登录浮层、⽹络异常界⾯、返回⾸页快捷导航、公众号关注组件等统⼀抽离成⼀个⽗公共组件,编写eslint规则要求所有页⾯统⼀引⼊,以此实现&保证登录时浮层存在。浮层⽆缝时序授权浮层AuthModal.wpy:<template><viewclass="modal"wx:if="{{show}}"><buttonopen-type="getUserInfo"bindgetuserinfo="onGetUserInfo">登录</button></view></template><script>importwepyfrom'wepy';exportdefaultclassextendsponent{data={show:false,listener:null,//结果监听}computed={}methods={onGetUserInfo(ev){//⽤户点击了授权按钮this.listener&&this.listener({//回调授权结果succeeded:ev.detail.errMsg.includes('ok'),data:ev.detail,});this.show=false;//关闭授权浮层this.$apply();}}//打开授权浮层open(){returnnewPromise((resolve,reject)=>{this.listener=resolve;//设置监听this.show=true;//打开浮层this.$apply();//⽤户操作结束后会触发监听回调'resolve',使当前Promiseresolve,从⽽⾃动继续执⾏后续登录步骤});}onUnload(){//页⾯卸载,⽤户未点击按钮直接返回在此处理this.listener&&this.listener({//授权失败回调succeeded:false,data:null,});}}</script>登录模块login.js:_loginSteps={asyncrequestUserInfo(){letpage=getCurrentWepyPage();//获取当前页⾯实例letuserInfoRes=awaitpage.$invoke('AuthModal','open');//打开授权浮层,并监听其操作结果//正常进⾏后续处理if(userInfoRes.succeeded)//授权成功后续处理...else//授权失败后续处理...}}如以上代码所⽰,虽然⾃定义浮层需要展⽰按钮、等待⽤户点击、处理点击、考虑⽤户不点击直接返回,交互流程相对复杂,但依然可以利⽤Promise使交互细节对外透明。打开浮层时返回⼀个Promise,在各个交互出⼝对Promise进⾏resolve,则使⽤时只需将其作为⼀个普通的异步过程对待。这样,就可以实现⽆缝接⼊⾃定义浮层授权。⽅案2:独⽴登录页需要授权⽤户信息时,跳转⾄⼀个专门的登录页⾯,页⾯中展⽰引导内容和授权<button>,⽤户操作完毕后再⾃动返回先前页⾯。实现元素引⼊登录所需dom元素只在登录页引⼊即可。页⾯⽆缝时序由于⼩程序的代码包特性,各页⾯可以共享全局变量和全局函数;并且后⼀页⾯打开时,前⼀页⾯依然驻留在内存中,前⼀页⾯遗留的异步任务也依然会继续执⾏。因⽽,可以在前⼀页⾯设置监听,在登录页进⾏回调:授权全局数据模块userAuthHub.js:exportdefault{_listeners:[],subscribe(listener){//前⼀页⾯设置监听this._listeners.push(listener);},notify(res){//登录页进⾏结果回调this._listeners.forEach(listener=>listener(res));this._listeners=[];},}登录模块login.js:importuserAuthHubfrom'../lib/userAuthHub';_loginSteps={asyncrequestUserInfo(){letuserInfoRes=awaitnewPromise((resolve,reject)=>{userAuthHub.subscribe(resolve);//监听授权结果wx.navigateTo({url:'/pages/login/login'});//打开登录页//登录页操作结束后会触发监听回调'resolve',使当前Promiseresolve,从⽽⾃动继续执⾏后续登录步骤});//正常进⾏后续处理if(userInfoRes.succeeded)//授权成功后续处理...else//授权失败后续处理...}}登录页login.wpy:<template><buttonopen-type="getUserInfo"bindgetuserinfo="onGetUserInfo">登录</button></template><script>importwepyfrom'wepy'importuserAuthHubfrom'../../lib/userAuthHub';exportdefaultclassextendswepy.page{data={userInfoRes:{//记录授权信息succeeded:false,data:null,}}methods={onGetUserInfo(ev){//⽤户点击了授权按钮this.userInfoRes={//记录结果succeeded:ev.detail.errMsg.includes('ok'),data:ev.detail,};wx.navigateBack();//返回原先页⾯}}onUnload(){//页⾯卸载,⽤户未点击按钮直接返回和点击按钮授权后页⾯⾃动返回两种场景在此处统⼀处理userAuthHub.notify(this.userInfoRes);//回调授权结果}}</script>如以上代码所⽰,虽然授权过程需要进⾏跨页⾯交互,但利⽤Promise和⼩程序代码包特性,可以在前⼀页⾯设置监听,登录页⾯进⾏回调。登录页⾯交互结束后,前⼀页⾯会⾃动继续执⾏登录流程,调⽤⽅⽆需进⾏返回刷新等额外处理,数据接⼝也会继续调⽤,⽤户⽆需再次操作。这样,就可以实现⽆缝接⼊跨页⾯授权交互。两种⽅案都可以实现⾃定义授权界⾯。内嵌浮层会增加⼀定维护成本和少量资源开销,但可以直接在当前页⾯完成登录交互,页⾯⾃定义空间也相对更⼤;独⽴登录页会来回跳转牺牲⼀定的交互体验,但可以把登录所需dom元素集中在登录页,减少维护成本和页⾯侵⼊。⼆者各有优劣,可以按需采⽤或混合使⽤。这样,我们的登录模块可以使⽤⾃定义授权界⾯,从⽽⽀持设计实现更雅观更精致的授权引导。复⽤优化多⼩程序间复⽤&定制问题:开发⽅可能同时维护着多个⼩程序,这些⼩程序使⽤着相同的后端接⼝和后端⽤户体系,⼜有着各⾃的⼩程序标识和使⽤诉求。⼀⽅⾯,希望登录模块可以统⼀维护,不需要每个⼩程序各⾃开发;另⼀⽅⾯,⼜希望各⼩程序可以进⾏差异化定制,包括⼩程序前端标识不⼀致等刚性差异,和授权提⽰⽂案、埋点、授权交互等个性差异。⽅案&实现:统⼀流程+个性化配置公共&默认流程由登录模块统⼀维护,各⼩程序直接复⽤;差异流程⽀持各⼩程序以配置的形式⾃定义扩展&覆盖。e.g.:classLogin{static_config={//可配置项/***刚需:⼩程序编号,⽤于区分不同的⼩程序,由后端分配*/source:'',/***个性化:⾃定义⽤户授权交互*@return{Promise<Object>}格式同wx.getUserInfo,或返回null使⽤默认授权逻辑*/userAuthHandler:null,//}static_loginSteps={//静默登录async_silentLogin({wxLoginRes}){letsilentRes=awaitLogin.request({url:'xxx/mpSilenceLogin',data:{code:wxLoginRes.code,source:Login._config.source,//⼩程序需要配置⾃⾝编号,后端根据编号找到正确的解码密钥和id映射表,进⾏静默登录}});//...},//获取微信⽤户信息asyncrequestUserInfo(){//⼩程序可以配置⾃定义授权交互,如:将授权交互改为⾃定义浮层/⾃定义登录页/...letuserInfoRes=Login._config.userAuthHandler&&awaitLogin._config.userAuthHandler();if(!userInfoRes)//若未配置⾃定义交互,亦提供默认授权交互userInfoRes=...;//}}}配置检查引⼊配置过程会存在⼀个潜在风险:触发登录时,⼩程序尚未完成登录模块配置。理论上,只要全局都使⽤同⼀个登录实例并在app.js顶部进⾏配置,应该就没有这样的时序风险。但复⽤⽅是不会⾃觉的,不⼀定会使⽤同⼀个实例,配置过程也不⼀定会被放在顶部,甚⾄有可能被放在某些异步数据返回之后。因⽽登录模块只导出唯⼀实例并加⼊配置检查环节以保证该逻辑健壮性:/***类修饰器,确保调⽤API时已完成⼩程序信息配置*@paramtargetLogin*/functionrequireConfig(target){for(letpropofObject.getOwnPropertyNames(target)){if(['arguments','caller','callee','name','length'].includes(prop))//内置属性,不予处理continue;if(typeoftarget[prop]!=="function")//⾮函数,不予处理continue;if(['config','install','checkConfig'].includes(prop)||prop[0]==='_')//配置/安装/检查函数、私有函数,不予处理continue;target[prop]=(function(oriFunc,funcName){//对外接⼝,增加配置检查步骤returnfunction(...args){if(!target.checkConfig()){//若未进⾏项⽬信息配置,则报错console.error('[Login]请先执⾏Login.config配置⼩程序信息,后使⽤Login相关功能:',funcName);return;}returnoriFunc.apply(this,args);//否则正常执⾏原函数}}(target[prop],prop));}}/***登录模块命名空间*/@requireConfig//确保调⽤API时已完成项⽬信息配置classLogin{/***登录*@param{Object}options登录选项*@param{string}options.mode登录模式*@return{Promise<Object>}res登录结果*/staticasynclogin(options){//...}/***要求登录态的数据请求*@param{Object}options请求参数,格式同wx.request*@param{Object}options.loginOpts登录选项,格式同login函数*@return{Promise}返回结果,resolve时为数据接⼝返回内容,reject时为请求详情*/staticasyncrequestWithLogin(options){//...}//@requireConfig修饰器会在login、request

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论