Vue微信开发中授权登录的优雅实现
前言微信授权登录是微信公众号开发中绕不开的话题,而整个授权登录流程的实现需要前后端的配合。以前前后端没有分离的时候,可能我们前端不需要太关心授权的具体实现。不过现在都2021年了,前后端分离的架构很流行。如何在前后端分离的情况下实现微信授权登录成为今天要讨论的重点问题。首先我们还是要梳理一下微信授权的整个流程。这里直接转官方文档:如果用户在微信客户端访问第三方网页,公众号可以利用微信网页授权机制获取用户基本信息实现业务逻辑。...关于网页授权两种scope的区别1、以snsapi_base为scope发起的网页授权,用于获取进入页面的用户openid,静默授权,自动跳转到回调页面。用户感知到的是直接进入回调页面(通常是业务页面)2、以snsapi_userinfo为scope发起的网页授权,用于获取用户的基本信息。但这种授权需要用户手动同意,既然用户已经同意,授权后无需关注即可获取用户的基本信息。...具体来说,网页授权流程分为四步:1.引导用户进入授权页面同意授权,获取code2,用code换取网页授权access_token(区别于access_token中的基础支持)3.开发者如有需要可以刷新网页授权access_token避免过期4.通过网页授权access_token和openid获取用户基本信息(支持UnionID机制??)。这里是微信♂开发的微信授权官方文档。以上是作者摘录的重点。当然,还有更多的解释。希望新手读者先仔细阅读官方文档。这里补充一下,在上述过程的四个步骤中,除了第一步,其他三个步骤都需要在服务器端完成。前端的核心其实就是如何检查判断用户登录状态,维护登录状态。众所周知,Vue是前后端分离技术解决方案的产物,是一个纯前端应用(服务端渲染除外)。通常,当用户打开页面,执行页面上的js脚本时,我们会异步请求服务器数据,然后进行相关逻辑的处理和判断。我们实现微信授权登录的前提是首先判断用户是否需要登录(cookie或token)。当用户未登录时,需要经过授权登录流程。授权登录成功后,我们还需要在前端记录登录状态,这样切换页面时就不用再次触发授权登录了。通过分析可以看出,前端其实可以做的就是获取微信服务器给我们的代码,然后把代码交给我们的后端,让后端完成接下来的获取步骤用户信息并生成用户。那么我把整个流程梳理如下:(前端)检查用户是否登录;(前端)如果未登录,引导用户进入授权页面同意授权,获取代码(前端)并将获取的代码通过codeinexchange提交给后端(back-end)对于用户凭证openid(backend)通过openid检查用户是否存在,是否需要注册新用户,获取用户id(backend)返回用户信息;(frontend)记录用户登录状态,并跳回登录前的页面;这个过程,我画了一张图,如下:上面的代码根据上面的思路,现在开始编码过程。作者使用Vue3,Vue2开发者请根据情况适当调整。为了方便用户授权登录逻辑,笔者打算将授权登录封为登录页面。这样做的好处是,我们可以在判断需要登录的地方直接通过VueRouter的push方法跳转到登录页面。通常我们的应用并不是所有的页面都需要登录才能访问。只有在访问特定页面时,用户才需要登录。这时我们需要识别哪些页面需要登录认证。这里我们可以使用VueRouter的meta属性来识别。官方文档对meta的解释是这样的:有时候,你可能想在路由上附加任意信息,比如transition名称,谁可以访问路由等等,这些东西都可以通过接收property对象的meta属性来实现,而在路由地址和导航守卫上都可以访问到。正好VueRouter有官方的例子,如下:requireslogintoaccess:{requiresAuth:true}},{path:':id',component:PostsDetail,//任何人都可以访问的页面meta:{requiresAuth:false}}]}]接下来,我们可以全局使用VueRouter守卫在beforeEach中获取此元信息以进行登录跳转router.beforeEach((to,from)=>{//而不是检查每个路由记录//to.matched.some(record=>record.meta.requiresAuth)if(to.meta.requiresAuth&&!userStore.isLogin){//此路由需要授权,请检查您是否已登录//如果没有,则重定向到登录页面return{path:'/login',//保存我们的位置以备后用:{redirect:to.fullPath},}}})需要添加的是userStore.isLogin的实现。这与我们实际采用的登录状态维护方案有关。如果使用token方法,就是检查token是否已经存在。笔者使用vuex保存token,然后使用插件将Store中的数据持久化到localStorage。接下来看具体实现:login.vue:登录组件
可以看到登录页面其实没有任何内容。跳转到这个页面后,我们会直接跳转到微信授权的页面,授权回调会返回这个页面,此时我们通过获取路由参数获取code参数@/hooks/usePage.ts:该文件主要封装了常见的路由器相关方法Path*/exportfunctionredirectTo(path:string){const{replace}=routerreplace({path,})}/***获取路由上的查询参数*/exportfunctiongetRouteQuery(){const{currentRoute}=routerconst{query}=currentRoute.valuereturncloneDeep(query)}@/hooks/useWechatAuth.ts:该文件封装了微信授权请求与后端交互import{useAxios}from'@/hooks/useAxios'/***获取微信授权的跳转地址*@paramcallbackUrl授权后的回调链接*@returns*/exportfunctionjump2Auth(callbackUrl:string){useAxios({url:'/api/wechat/auth',params:{redirect_url:callbackUrl,},}).then((authUrl:any)=>{if(process.env.NODE_ENV==='development'){window.location.href=callbackUrl+'?code=test'}else{window.location.href=authUrl}})}/***提交登录代码*@paramcode*@returns*/exportasyncfunctiongetUserInfo(code:string){constuserInfo=awaituseAxios({method:'POST',url:'/api/wechat/auth',params:{code,},})returnuserInfo}@/store/modules/user.ts:全局状态存储,主要是登录前记录token和访问页面../globals'interfaceUserState{token:stringlandPageRoute:string}constNAME='user'//name:模块名//namespaced表示开启命名空间//当dynamic设置为true时表示创建一个动态module,运行时会创建将模块注册到storage//preserveState如果数据是持久化的,变量为true时可以从storage中获取初始值@Module({namespaced:true,name:NAME,dynamic:true,store,preserveState:Boolean(initialUnencryptedStorage[NAME]),})exportclassUserextendsVuexModule{userState:UserState={token:'',/**复制代码登录前访问页面*/landPageRoute:'',}getisLogin():boolean{return!!this.userState.token}@MutationsaveToken(token:string):void{this.userState.token=到ken}@MutationsetLandPage(route:string):void{this.userState.landPageRoute=route}}exportconstuserStore=getModule
(User)作者使用vuex-persistedstate插件来存储store中的数据到本地存储。好处是用户关闭页面后再次访问,也就是不需要重新触发微信授权流程,大大优化了用户体验看效果。笔者在微信开发者工具上使用自主开发的公众号应用来演示效果。首先清空所有缓存,模拟新用户登录效果,然后打开笔者的公众号应用,触发页面跳转鉴权,点击同意,触发微信授权回调,提交代码登录即可看到登录后的用户令牌已成功写入localStorage。可以搜索微信公众号“下单小站”自行体验(找bug)。另外,授权登录的完整实现代码已经托管在github上。单击以查看摘要。不得不说,Vue3在代码抽象和复用上写起来真的很舒服。逻辑代码解耦分离,hook一个一个生成,让代码看起来优雅很多。笔者尝试演示该方案后,无论是在代码的干净优雅,还是在业务需求的实现上,都近乎完美(请允许我假扮一波b)。当然,可能还有我这里没有发现的bug或者痛点。毕竟,从来没有完美的架构。在此,也欢迎大家与我共同探讨,提供更好的解决方案和思路。写在最后,最近有点闲。打算用Vue3+ts+vant从零开始完成一个公众号应用,分享一下开发过程。也算是一种激励自己继续学习的方式。如果您有想法和建议,欢迎和我一起讨论。同时,为了方便大家更好的讨论微信公众号开发相关技术,笔者还建立了一个微信群,欢迎加入,与大家一起学习成长。微信扫描下方二维码即可申请入群