Vue3项目中优雅实现微信授权登录的方法

目录
  • 前言
  • 准备
  • 实现思路
  • 上代码
  • 总结

前言

微信授权登录是做微信公众号开发一直绕不开的话题,而且整个授权登录流程的实现,是需要前后端配合一起完成的。在过去前后端还未分离的年代,也许我们前端并不需要太过关心授权的具体实现。然而现在都2021年了,前后端分离的架构大行其道,如何在前后端分离的情况下实现微信授权登录就成了今天要探讨的重点问题。

准备

首先,我们还是需要先梳理下微信授权整个流程是怎样的,这里我就直接将官方文档搬来:

如果用户在微信客户端中访问第三方网页,公众号可以通过微信网页授权机制,来获取用户基本信息,进而实现业务逻辑。

...

关于网页授权的两种scope的区别说明

1、以snsapi_base为scope发起的网页授权,是用来获取进入页面的用户的openid的,并且是静默授权并自动跳转到回调页的。用户感知的就是直接进入了回调页(往往是业务页面)

2、以snsapi_userinfo为scope发起的网页授权,是用来获取用户的基本信息的。但这种授权需要用户手动同意,并且由于用户同意过,所以无须关注,就可在授权后获取该用户的基本信息。

...

具体而言,网页授权流程分为四步:

1、引导用户进入授权页面同意授权,获取code

2、通过code换取网页授权access_token(与基础支持中的access_token不同)

3、如果需要,开发者可以刷新网页授权access_token,避免过期

4、通过网页授权access_token和openid获取用户基本信息(支持UnionID机制)

这里附上微信公众号开发之微信授权的官方文档

以上是笔者提炼出来的比较关键的几点信息,当然还有更多的说明,希望新手读者们还是先认真看完官方文档。

这里我再补充说明下,以上流程的4个步骤中,除了第一步以外,另外三步都是需要在服务器端去完成的。前端要做的核心其实是怎么进行用户登录状态的检查判断和登录状态的维护。

实现思路

大家都知道,Vue是前后端分离技术方案下的产物,它是一个纯前端应用(服务端渲染除外)。通常我们是需要在用户打开页面,执行到页面的js脚本时,我们再异步去请求服务端数据,再进行相关逻辑的处理和判断。我们要实现微信授权登录的前提是,需要先判断用户是否需要登录(cookie或者token)。当用户未登录时,才需要走授权登录流程,当授权登录成功后,我们也需要在前端记录好登录状态,以方便在页面切换时,不用再次触发授权登录。再通过分析可知,前端其实能做的就是获取微信服务器给我们的code,再将code给我们的后端,让后端完成后续步骤拿到用户信息后生成用户。那么整个过程我再梳理如下:

  1. (前端)检查用户是否登录;
  2. (前端)如果未登录,引导用户进入授权页面同意授权,获取code
  3. (前端)将获取到的code提交给后端
  4. (后端)通过code换取用户凭证openid
  5. (后端)通过openid检查用户是否存在,是否需要注册新用户,并获取用户id
  6. (后端)返回用户信息;
  7. (前端)记录用户登录状态,跳回登录前页面;

这个过程,我画了个图,如下:

上代码

根据以上思路,现在开始编码环节。笔者采用的是Vue3,Vue2的开发者还请根据情况做适当调整。
为了方便唤起用户授权登录逻辑,笔者打算将授权登录封住为一个login页面,这样做的好处是我们在任何判断到需要登录的地方直接通过Vue Router的push方法跳转到登录页面即可。

通常情况下,我们的应用并不是所有页面都需要登录后才能访问,只有在访问特定页面时候,才需要用户登录,那么我们就需要标识哪些页面需要进行登录鉴权。这里我们可以利用Vue Router的meta属性来进行标识,官方文档对meta解释如下:

有时,你可能希望将任意信息附加到路由上,如过渡名称、谁可以访问路由等。这些事情可以通过接收属性对象的meta属性来实现,并且它可以在路由地址和导航守卫上都被访问到。

刚好Vue Router官方就有示例,如下:

const routes = [
  {
    path: '/posts',
    component: PostsLayout,
    children: [
      {
        path: 'new',
        component: PostsNew,
        // 需要登录后才能访问的页面
        meta: { requiresAuth: true }
      },
      {
        path: ':id',
        component: PostsDetail,
        // 任何人都可访问的页面
        meta: { requiresAuth: false }
      }
    ]
  }
]

接下来我们就可以在Vue Router的全局守卫beforeEach中获取到这个元信息从而做登录跳转了

router.beforeEach((to, from) => {
  // 而不是去检查每条路由记录
  // to.matched.some(record => record.meta.requiresAuth)
  if (to.meta.requiresAuth && !userStore.isLogin) {
    // 此路由需要授权,请检查是否已登录
    // 如果没有,则重定向到登录页面
    return {
      path: '/login',
      // 保存我们所在的位置,以便以后再来
      query: { redirect: to.fullPath },
    }
  }
})

需要补充说明的是,userStore.isLogin的实现。这里和我们实际采用的登录态维护方案有关,如果是采用token方式的话,那就是检查token是否已经存在。笔者采用了vuex作为来保存token,然后借助插件来将Store中的数据持久化到localStorage。

接下来我们来看具体的实现:

login.vue: 登录组件

<template>
  <div class="login"></div>
</template>

<script lang="ts">
import { defineComponent } from 'vue'

import { jump2Auth, getUserInfo } from '@/hooks/useWechatAuth'
import { userStore } from '@/store/modules/user'
import { redirectTo, getRouteQuery } from '@/hooks/usePage'

export default defineComponent({
  name: 'Login',
  setup() {
    let code = getRouteQuery().code as string
    // 3.如果有code,则已经授权
    if (code) {
      getUserInfo(code as string).then((res: any) => {
        // 记录token
        userStore.saveToken(res.access_token)
        const redirect = userStore.userState.landPageRoute || '/'
        // 跳转到授权前访问的页面
        redirectTo(redirect)
      })
    } else {
      // 1.记录上一个页面的地址
      const { redirect } = getRouteQuery()
      if (redirect) {
        userStore.setLandPage(redirect as string)
      }
      // 2.跳转授权
      const callbackUrl = window.location.origin + window.location.pathname
      jump2Auth(callbackUrl)
    }
  },
})
</script>

可以看到,login页面其实并没有什么内容,跳转到该页面后,我们会直接重定向到微信授权的页面,授权回调回来也会回到该页面,此时我们再通过获取路由参数的方式获取code参数。

@/hooks/usePage.ts: 该文件主要是封装了router相关的常用方法

import router from '@/router'
import { cloneDeep } from 'lodash'
import { toRaw } from 'vue'

/**
 * 重定向
 * @param path 路径
 */
export function redirectTo(path: string) {
  const { replace } = router
  replace({
    path,
  })
}

/**
 * 获取路由上query参数
 */
export function getRouteQuery() {
  const { currentRoute } = router
  const { query } = currentRoute.value
  return cloneDeep(query)
}

@/hooks/useWechatAuth.ts:该文件封装了微信授权与后端交互的请求

import { useAxios } from '@/hooks/useAxios'

/**
 * 获取微信授权的跳转地址
 * @param callbackUrl 授权后回调链接
 * @returns
 */
export function jump2Auth(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
    }
  })
}

/**
 * 提交code进行登录
 * @param code
 * @returns
 */
export async function getUserInfo(code: string) {
  const userInfo = await useAxios({
    method: 'POST',
    url: '/api/wechat/auth',
    params: {
      code,
    },
  })
  return userInfo
}

@/store/modules/user.ts: 全局状态存储,主要是记录token和登录前访问页面

import { Module, VuexModule, Mutation, getModule, Action } from 'vuex-module-decorators'
import store from '@/store'
import { initialUnencryptedStorage } from '../globals'

interface UserState {
  token: string
  landPageRoute: string
}

const NAME = 'user'
// name: 模块名字
// namespaced 表示开启命名空间
// dynamic设置为true时,表示创建动态模块,运行时将模块注册到存储中
// preserveState 如果数据有持久化,该变量为true时可以从storage中拿取初始值
@Module({
  namespaced: true,
  name: NAME,
  dynamic: true,
  store,
  preserveState: Boolean(initialUnencryptedStorage[NAME]),
})
export class User extends VuexModule {
  userState: UserState = {
    token: '',
    /** 登录前访问页面 */
    landPageRoute: '',
  }

  get isLogin(): boolean {
    return !!this.userState.token
  }

  @Mutation
  saveToken(token: string): void {
    this.userState.token = token
  }

  @Mutation
  setLandPage(route: string): void {
    this.userState.landPageRoute = route
  }
}

export const userStore = getModule<User>(User)

笔者借助vuex-persistedstate插件将store中数据存储到了localStorage,这样做的好处是用户关闭页面后,再次访问,即不用重新触发微信授权流程,大大优化了用户体验。

总结

不得不说,Vue3在代码抽象和复用这块上,写起来着实舒服很多,希望大家也也尝试着按照官方实践那样,多将逻辑代码解耦抽离,生成一个个的hook,这样代码就显得优雅多啦。该方案经过笔者尝试论证,不论是代码整洁优雅程度,还是业务需求的实现上,都几乎完美(请容我装一波b)。当然,这里可能存在我没发现的bug或者痛点,毕竟从来没有十全十美的架构嘛,这里也欢迎看官大佬们和我交流探讨,提供更好的方案和想法。

到此这篇关于Vue3项目中优雅实现微信授权登录的文章就介绍到这了,更多相关Vue3微信授权登录内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 详解vue微信网页授权最终解决方案

    vue微信网页授权,基于vue-cli3.0+webpack 4+vant ui + sass+ rem适配方案+axios,开发的微信授权方案.项目地址:vue-wechat-auth 参考了[vue-wechat-login],思路有些不同,本文基于进入所有页面都必须先授权的操作. 与之前写的授权不同之处 这次的逻辑全部在router的beforeEach进行,相较更加简洁明.之前是在一个中间页author.vue中,加上微信授权要跳转很多次 在这里你能找到 微信网页授权前端解决方案,官方文

  • vue 授权获取微信openId操作

    1.获取url中参数code: 根据code 获取openId:调用后台接口获取openId . 参考文档:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140842 function getUrlKey(name){//获取url 参数 return decodeURIComponent((new RegExp('[?|&]'+name+'='+'([^&;]+?)(&|#|;|$)').exec(l

  • VueJs单页应用实现微信网页授权及微信分享功能示例

    在实际开发中,无论是做PC端.WebApp端还是微信公众号等类型的项目的时候,或多或少都会涉及到微信相关的开发,最近公司项目要求实现微信网页授权,并获取微信用户基本信息的功能及微信分享的功能,现在总算完成了,但开发过程中遇到好几个坑.废话不多说了,开始正题. 描述点 微信相关开发知识了解 怎么样实现微信相关功能本地测试 微信网页授权 微信分享 微信相关开发知识了解 微信公众号的appId,AppSecret 当我们注册一个微信公众号后,便能够得到一个appId(每个微信公众号只有一个,一个微信公

  • 详解Vue微信授权登录前后端分离较为优雅的解决方案

    微信授权登录是一个非常常见的场景,利用微信授权登录,我们可以很容易获取用户的一些信息,通过用户对公众号的唯一openid从而建立数据库绑定用户身份. 微信授权登录的机制这里不做详述,微信官方文档已有详述,简述就是通过跳转微信授权的页面,用户点击确认后,微信会跳到回调页面,此时回调页面url上会携带code参数,通过code参数,后端可以拿code换取拥护openid,或者用户信息 在vue项目中,通常是一个SPA应用,即所有的页面都是同一个html,通常现在开发也是前后端彻底分离的,vue打包后

  • vue 微信授权登录解决方案

    背景 vue前后端分离开发微信授权 场景 app将商品分享到微信朋友圈或者分享给微信好友,用户点击页面时进行微信授权登陆,获取用户信息. 问题:没有固定的h5应用首页.授权后重定向url带参数并且很长 本人愚钝,开发过程中,尝试过很多方法,踩坑不足以形容我的心情,可以说每一次都是一次跳井的体验啊. 1.一开始是前端请求微信连接,返回code,然后code作为再去请求后台接口获取token,后面看到别人的博客说这个方法不好,最好就是直接请求后台接口,然后后台返回url做跳转,所以就采用了最传统的方

  • Vue微信项目按需授权登录策略实践思路详解

    项目采用Vue作为开发框架,用户浏览页面时有两种情况: 一种是需要用户先登录之后才能继续浏览: 另一种是用户无需登录即可随意浏览. 在无需用户登录的页面中,可能包含需要用户信息的操作,此时就需要用户登录之后方能进行后续操作.因此,需要对授权登录策略进行区分. 思路 1.一般而言,我们为微信开发的H5页面,进入页面的时候就进行鉴权,要求用户登录之后才能继续浏览.但由于产品需求,这个项目我们需要对不同页面的鉴权策略进行划分,按照一般与特殊进行设计: 2.一般情况,用户进入页面第一时间要求用户授权登录

  • vue移动端微信授权登录插件封装的实例

    1.新建wechatAuth.js文件 const queryString = require('query-string') //应用授权作用域,snsapi_base (不弹出授权页面,直接跳转,只能获取用户openid),snsapi_userinfo (弹出授权页面,可通过openid拿到昵称.性别.所在地.并且,即使在未关注的情况下,只要用户授权,也能获取其信息) const SCOPES = ['snsapi_base', 'snsapi_userinfo'] class VueWe

  • Vue3项目中优雅实现微信授权登录的方法

    目录 前言 准备 实现思路 上代码 总结 前言 微信授权登录是做微信公众号开发一直绕不开的话题,而且整个授权登录流程的实现,是需要前后端配合一起完成的.在过去前后端还未分离的年代,也许我们前端并不需要太过关心授权的具体实现.然而现在都2021年了,前后端分离的架构大行其道,如何在前后端分离的情况下实现微信授权登录就成了今天要探讨的重点问题. 准备 首先,我们还是需要先梳理下微信授权整个流程是怎样的,这里我就直接将官方文档搬来: 如果用户在微信客户端中访问第三方网页,公众号可以通过微信网页授权机制

  • 利用Spring Social轻松搞定微信授权登录的方法示例

    微信第三方登录有两种方式:扫码登录(微信开放平台)和公众号登录(微信公众平台) 扫码登录可以用于PC等跨平台应用,而公众平台必须在微信app内使用,且必须关注公众号. 下面以公众平台为例,介绍如何基于Spring Social实现微信用户授权并获取到用户信息.(微信开放平台类似) 第一步:到微信公众平台后台注册应用并进行相关设置 微信公众平台后台地址: https://mp.weixin.qq.com/ 也可以先注册一个测试号: https://mp.weixin.qq.com/debug/cg

  • ajax 实现微信网页授权登录的方法

    项目背景 因为项目采用前后端完全分离方案,所以,无法使用常规的微信授权登录作法,需要采用 ajax 实现微信授权登录. 需求分析 因为本人是一个phper ,所以,微信开发采用的是 EasyWeChat ,所以实现的方式是基于EW的. 其实实现这个也麻烦,在实现之前,我们需要了解一下微信授权的整个流程. 引导用户进入授权页面同意授权,获取code 通过code换取网页授权access_token(与基础支持中的access_token不同) 如果需要,开发者可以刷新网页授权access_toke

  • IOS实现微信授权登录功能

    微信是一个在开发中经常会使用到的平台,比如微信登录.授权.支付.分享.今天我们来看看如何在自己的应用里面集成微信授权. 1.微信授权的定义 微信OAuth2.0授权登录让微信用户使用微信身份安全登录第三方应用或网站,在微信用户授权登录已接入微信OAuth2.0的第三方应用后,第三方可以获取到用户的接口调用凭证(access_token),通过access_token可以进行微信开放平台授权关系接口调用,从而可实现获取微信用户基本开放信息和帮助用户实现基础开放功能等. 2.微信授权的步骤 第三方发

  • Android开发:微信授权登录与微信分享完全解析

    前言 在移动互联网浪潮中,联网APP已经把单机拍死在沙滩上,很多公司都希望自家应用能够有一套帐号系统,可是许多用户却并不一定买账:我凭啥注册你家应用的帐号?微博,微信,QQ几乎成了每个人手机中的必装应用,于是微信,微博,QQ说了:来来来,你们都可以用我家的帐号登录你家应用,只要你遵循OAuth2.0协议标准就行.于是第三方社交帐号登陆成为了许多新兴应用的选择,由于腾讯官方微信开放平台的在线文档相对最新的SDK有些出入,并且登录相关的文档结构次序有些紊乱,今天就把我的一些经验记录在此,对微信开放平

  • Django项目中实现使用qq第三方登录功能

    使用qq登录的前提是已经在qq互联官网创建网站应用并获取到QQ互联中网站应用的APP ID和APP KEY 1,建路由 # qq登录 path('loginQq/',qq.loginQq,name='loginQq/'), path('returns/',qq.returns,name='returns/'), 2,前端页面写qq登录的链接,本文没有用图标,暂时使用a链接请求. <a data-wow-delay=".5s" href="/blog/loginQq/&q

  • Vue3+Vue-cli4项目中使用腾讯滑块验证码的方法

    简介: 滑块验证码相比于传统的图片验证码具有以下优点: 验证码的具体验证不需要服务端去验证,服务端只需要核验验证结果即可. 验证码的实现不需要我们去了解,也不需要我们去具体实现. 滑块验证码的安全程度相比于传统验证码高不少. ... 由于网络上和腾讯api文档中缺少关于vue3中组合式api怎么应用腾讯的滑块验证码,所以出此教程.本人也非vue大佬,对vue的理解也不过停留在初级使用的程度上,有错误之处,敬请指出. 开始: 首先,我们需要去腾讯云申请一个图形验证的api,使用场景中选择自己的使用

  • vue项目中实现的微信分享功能示例

    本文实例讲述了vue项目中实现的微信分享功能.分享给大家供大家参考,具体如下: /* 微信分享 */ Vue.prototype.wechatShare = (shareData) => { let resource = { title: '随我心愿!', desc: '体验优质服务', link: 'https://www.abc.cn/', img: 'https://www.abc.cn/images/share_logo.jpg' } let obj = Object.assign({}

随机推荐