这篇文章也发在我的博客, 欢迎围观 http://52.221.251.163/archives/152
写在前面
项目采用 vue 作为开发框架, 用户浏览页面时有两种情况:
一种是需要用户先登录之后才能继续浏览;
另一种是用户无需登录即可随意浏览.
在无需用户登录的页面中, 可能包含需要用户信息的操作, 此时就需要用户登录之后方能进行后续操作. 因此, 需要对授权登录策略进行区分.
思路
一般而言, 我们为微信开发的 H5 页面, 进入页面的时候就进行鉴权, 要求用户登录之后才能继续浏览. 但由于产品需求, 这个项目我们需要对不同页面的鉴权策略进行划分, 按照一般与特殊进行设计:
一般情况, 用户进入页面第一时间要求用户授权登录, 按照常规的微信授权登录流程, 登录之后, 用户继续浏览.
特殊情况, 为无需用户登录的页面配置白名单, 只要进入存在于白名单的路由, 不进入检测用户登录状态的函数, 直接渲染页面.
对于用户未登录状态下进行的需要用户信息的操作, 按照我目前的理解, 即使是基于微信的静默授权, 页面也必须重新刷新, 无法做到真正无感授权并且继续用户的操作. 因此我选择在前端层面给用户更友好的提示, 让用户了解授权过程, 缺点是前一次操作仅仅是触发授权登陆, 授权登录后, 用户需要再次进行操作.
- // routerRule.js
- export default function routerRule (router, whiteList = []) {
- // other codes...
- router.beforeEach( (to, from, next ) => {
- // 因为授权登录涉及异步操作, 因此使用 promise, 成功的回调中调用 next 函数
- new Promise((resolve, rejects) => {
- if ( whiteListRouter.indexOf(to.path) !== -1 ) {
- resolve()
- return
- }
- // 常规页面授权登录过程
- if (hasToken()) {
- // codes, 获取用户信息并且跳转所需跳转的页面
- } else {
- // 判断用户是否已经进行微信授权
- if (hasAuthed()) {
- // 进行过微信授权之后, 重定向回来的 url 中包含了微信的授权信息, 可以将 url 上截取的参数发送到服务器, 换取用户的 token, 随后进入上述有 token 时候的步骤
- getWechatUserInfo().then(res => {
- resolve()
- })
- } else {
- // 用户尚未进行微信授权, 则调用微信授权的方法, 进行授权登录.
- getWechatAuth()
- }
- }
- }).then( res => {
- next()
- })
- })
- router.afterEach(( to, from ) => {
- wxShare({ title: to.meta.title, desc: to.meta.shareDesc, link: to.meta.shareLink, logo: to.meta.shareLogo})
- })
- }
本项目是在用户初次进行微信绑定时, 就将用户的微信信息与本站的用户信息进行的绑定, 因此在获取用户微信授权信息后, 就可以获取到用户的 token, 从而获取用户在本站的其他用户信息.
在无需登录页面的进行需要权限的操作的处理
根据上面的逻辑, 进入白名单之后, 整个函数已经被 return 掉, 不会进入下面的鉴权过程. 但是如果是在此种页面上进行需要权限的操作, 那么就需要触发授权登录流程, 并且在授权之后, 要一并获取用户信息.
- // checkLogin.js
- export function checkLogin({ redirectUrl, wxAuthLoading, wxAuthLoaded, callback } = {}) {
- if (getToken()) {
- // ...
- callback && callback()
- } else {
- // 提示用户正在授权中
- wxAuthLoading && wxAuthLoading()
- getWechatAuth( redirectUrl || window.location.href ).then( res => {
- // 授权完毕, 提示用户授权成功
- wxAuthLoaded && wxAuthLoaded()
- })
- }
- }
同时, 我们需要对路由白名单添加一些操作
- // routerRule.js
- export default function routerRule (router, whiteList = []) {
- // other codes...
- router.beforeEach( (to, from, next ) => {
- // 因为授权登录涉及异步操作, 因此使用 promise, 成功的回调中调用 next 函数
- new Promise((resolve, rejects) => {
- if ( whiteListRouter.indexOf(to.path) !== -1 ) {
- // 如果已经进行微信授权但是没有 token 值的, 就调用以下函数获取 token 值
- if ( !hasToken() && hasAuthed() ) {
- getWechatUserInfo().then(res => {
- resolve()
- })
- }
- resolve()
- return
- }
- // 常规页面授权登录过程
- if (hasToken()) {
- // codes, 获取用户信息并且跳转所需跳转的页面
- } else {
- // 判断用户是否已经进行微信授权
- if (hasAuthed()) {
- // 进行过微信授权之后, 重定向回来的 url 中包含了微信的授权信息, 可以将 url 上截取的参数发送到服务器, 换取用户的 token, 随后进入上述有 token 时候的步骤
- getWechatUserInfo().then(res => {
- resolve()
- })
- } else {
- // 用户尚未进行微信授权, 则调用微信授权的方法, 进行授权登录.
- getWechatAuth()
- }
- }
- }).then( res => {
- next()
- })
- })
- // other codes...
- }
坑点以及不完善的地方
这个方案在用户授权之后, 在路由跳转之前, 一定要先获取用户信息, 否则在 url 上的微信授权信息就会丢失, 获取用户信息就会失败.
这个方案的缺点在于, 需要开发者对在免登陆页面的所有需权限操作都加上 checkLogin 判断. 由于这种需权限的操作一般都是发送异步请求, 所以如果不考虑减少不必要的异步请求的情况下, 可以统一在请求的方法上设置拦截器, 判断后端返回的 code, 如果返回的是用户未登录的 code, 就进行微信授权. 这种做法开发过程比较方便, 但是会在用户未登录情况下发送了一些不必要的请求给后端, 感觉不太好.
这是本人开发过程中想到的不成熟的方案, 如果有更好的方法, 请不吝告知, 谢谢!
来源: https://juejin.im/post/5aef2db3f265da0b9c10899e