项目地址:https://github.com/PassionZale/3Years
许多想在微信公众号开发使用 SPA 架构的开发者,往往第一个拦路虎便是微信的 OAuth2.0 授权登录。
困难之处,或者说是棘手之处便是:服务端获取到 Openid 后如何告知 SPA 应用?
大部分情况下,我所接触过的项目均为 SPA,而非 MPA。经历过数个项目,我自己总结了几个微信授权场景下的前后端处理方式。
以下两种方式,前提条件为前后端项目均在同一个根域之下。
index.html 由服务端渲染
首先大部分开发者应该都明白,每个 SPA 项目都只有一个 HTML 文件,通常为 index.html。
如果你还折腾过服务端的开发,那么你也会知道,每种服务端语言,也都有自己的模板引擎。例如 Java、PHP、Python,它们都有自己的一个或者多个模板引擎。
拿 Laravel 的 .blade.php
模板引擎来讲,在模板引擎中,通过模板引擎所给予的界定符,可以让 HTML、PHP 得到混合编写。只需要服务端获取到 Openid,将其通过混编,赋值给 Javascript 的某个全局变量,这样 SPA 中任意模块或组件都可以从 window 对象中获取到 Openid 。当然不限于 Openid,你还可以根据实际业务需要,存储一些其他的数据,如用户名、邮费、购物车总数等等。
举个简单的例子,有点类似这样:
window.OPENID = "<?php $openid;?>";
和我们将 Laravel 的 csrf_token 放置在 <meta>
标签中如出一辙:
<meta id="csrf-token" content="{{ csrf_token() }}">
index.html 与服务端完全分离
这种情况,便是 3Years 中准备处理的场景。
在这种场景下,我们需要在前端存储 Openid,可以使用许多技术完成该缓存,例如:cookie、localStorage、vuex 等。
由于页面不是由服务端输出的,因此前端自身无法直接拿到 Openid。假设在 vuex 中你存储了 Openid,那么每当 SPA 任意路由首次被访问时,Openid 一定是空。
此时,我们可以在 vue-router 中的钩子函数中,进行一次拦截。拦截只做一件事情:
1. 获取当前的 transition.to.path
,并使用 encodeURIComponent
编码,将其作为参数 redirect
传入我们的授权中间路由或组件:Auth.vue;
2. 在 Auth.vue 中,开始读取 cookie,若 Openid 存在,则将 redirect
进行 decodeURIComponent
解码,使用 $router.push() 将当前路由重定向到对应的 redirect
中。
3. 若 Openid 不存在,则拼装链接,让服务端再次发起微信授权,写入 cookie,重定向到 redirect
对应的 SPA 路由。
在 main.js 中加入 vue-router 钩子:
在 Auth.vue 中读取 cookie:
服务端发起微信授权