preface

Wechat authorized login is to do wechat public number development has been around the topic, and the realization of the entire authorized login process, is the need to be completed together with the front and back end. In the past, when there was no separation of the front and back ends, maybe we didn’t need to worry too much about the implementation of authorization. However, it is now 2021 and the architecture of front and back end separation is popular. How to realize wechat authorized login in the case of front and back end separation has become the key issue to be discussed today.

To prepare

First of all, we still need to sort out the whole process of wechat authorization. Here I will directly move the official documents:

If a user accesses a third-party web page in the wechat client, the public account can obtain the user’s basic information through the wechat web page authorization mechanism, so as to realize the business logic.

Description of the difference between the two scopes of web page authorization

  1. The web page authorization initiated by snsapi_base for scope is used to get the OpenID of the user entering the page, and is silently authorized and automatically jumps to the callback page. What users perceive is that they are going straight to the callback page (usually the business page)
  2. The web page authorization initiated by snsapi_userinfo for scope is used to obtain the basic information of the user. However, this authorization requires the user’s manual consent, and since the user has agreed, the basic information of the user can be obtained after authorization without concern.

Specifically, the web page authorization process is divided into four steps:

  1. Enter the authorization page to approve authorization and obtain the code
  2. Exchange web page authorization access_token with code (different from access_token in base support)
  3. If necessary, developers can refresh the web license access_token to avoid expiration
  4. Access to basic user information through web authorization Access_token and OpenID (support UnionID mechanism)

Attached here is the official document of wechat authorization for the development of wechat public account.

The above are the key points extracted by the author, of course, there are more explanations, I hope the novice readers still carefully read the official document.

Here I would like to add that in addition to the first step of the above four steps, the other three steps need to be completed on the server side. The core of the front end is how to check and judge the user login status and maintain the login status.

Implementation approach

As you all know, Vue is the product of the front and back end separation technology solution, and it is a pure front-end application (except server side rendering). Usually, when the user opens the page and executes the JS script on the page, we asynchronously request the server data, and then process and judge the relevant logic. To realize wechat authorized login, we need to determine whether the user needs login (cookie or token). Only when the user does not log in, the user needs to go through the login authorization process. After the login is successful, the user needs to record the login status in the front end, so that the user does not need to trigger the login authorization again when the page is switched. Through further analysis, it can be seen that what the front end can do is to obtain the code given to us by the wechat server, and then give the code to our back end, so that the back end can complete the following steps to get the user information and generate users. Then the whole process is sorted as follows:

  1. (Front-end) Check whether the user is logged in;
  2. (Front end) If you have not logged in, access the authorization page and obtain the code
  3. (The front end) submits the code obtained to the back end
  4. (Back end) Exchange user credentials openID through code
  5. (Back-end) Check whether the user exists through OpenID, whether a new user needs to be registered, and obtain the user ID
  6. (backend) returns user information;
  7. (Front end) Record the user login status and jump back to the previous page;

I drew a picture of this process as follows:

In the code

According to the above ideas, now start coding. The author is using Vue3, the developers of Vue2 also please make appropriate adjustments according to the situation. In order to arouse the user’s authorized login logic, the author intends to seal the authorized login as a login page. The advantage of this is that we can directly jump to the login page through the push method of Vue Router wherever we judge that we need to login. In general, not all pages of our application need to be logged in to access. Users need to log in only when accessing specific pages. Therefore, we need to identify which pages need login authentication. Here we can use the meta attribute of Vue Router to identify meta. The official document explains meta as follows:

Sometimes, you may want to append arbitrary information to the route, such as the transition name, who can access the route, and so on. This can be done by receiving the meta attribute of a property object, and it can be accessed on both the routing address and the navigational guard.

Vue Router Router Router Router Router Router Router Router Router Router Router Router Router

const routes = [
  {
    path: '/posts'.component: PostsLayout,
    children: [{path: 'new'.component: PostsNew,
        // A page that requires login to access
        meta: { requiresAuth: true}}, {path: ':id'.component: PostsDetail,
        // Anyone can access the page
        meta: { requiresAuth: false}}]}]Copy the code

We can then get this meta information in the Vue Router’s global guard beforeEach to make a login jump

router.beforeEach((to, from) = > {
  // Instead of checking every routing record
  // to.matched.some(record => record.meta.requiresAuth)
  if(to.meta.requiresAuth && ! userStore.isLogin) {// This route requires authorization. Please check whether you have logged in
    // If not, redirect to the login page
    return {
      path: '/login'.// Save our location so we can come back later
      query: { redirect: to.fullPath },
    }
  }
})
Copy the code

One caveat is the implementation of userStore.islogin. Here is related to the actual login maintenance scheme we use, if the token mode is used, that is to check whether the token already exists. The author uses VUex as the token Store, and then uses the plug-in to persist the data in Store to localStorage.

Let’s look at the implementation:

Login. vue: login component

<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. If (code) {getUserInfo(code as string).then((res: Record any) = > {/ / token userStore. SaveToken (res) access_token) const redirect. = userStore userState. LandPageRoute | | '/' / / RedirectTo (Redirect)})} else {// 1 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>Copy the code

It can be seen that there is no content in the login page. After jumping to this page, we will be directly redirected to the page authorized by wechat, and the authorization callback will also return to this page. At this time, we will obtain the code parameter by obtaining routing parameters. @/hooks/ usepage.ts: This file mainly encapsulates common methods related to the router

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

/** * redirect *@param Path the path * /
export function redirectTo(path: string) {
  const { replace } = router
  replace({
    path,
  })
}

/** * Get the query parameter */ on the route
export function getRouteQuery() {
  const { currentRoute } = router
  const { query } = currentRoute.value
  return cloneDeep(query)
}
Copy the code

@/hooks/ usewechatauth.ts: This file encapsulates requests for wechat authorization to interact with the backend

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

/** * Obtain wechat authorized jump address *@param CallbackUrl Callback link after authorization *@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
    }
  })
}

/** * Submit code for login *@param code
 * @returns* /
export async function getUserInfo(code: string) {
  const userInfo = await useAxios({
    method: 'POST'.url: '/api/wechat/auth'.params: {
      code,
    },
  })
  return userInfo
}

Copy the code

@/store/modules/user.ts: global state storage, mainly to record the token and access page before login

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: module name
// namespaced indicates that the namespace is enabled
// Dynamic when set to true, dynamic modules are created and registered with storage at runtime
// preserveState If data is persistent, the initial value can be fetched from storage when the variable is true
@Module({
  namespaced: true.name: NAME,
  dynamic: true,
  store,
  preserveState: Boolean(initialUnencryptedStorage[NAME]),
})
export class User extends VuexModule {
  userState: UserState = {
    token: ' './** Access the page */ before login
    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)
Copy the code

The author uses Vuex-PersistedState to store data in store to localStorage. The advantage of this method is that users close the page and access it again without triggering wechat authorization process again, which greatly optimizes user experience.

See the effect

The following author uses the public account application developed by himself to demonstrate the effect on wechat developer tools. First, all caches are cleared to simulate the login effect of new users

Then open the author’s public number application, trigger page jump authentication

Click Agree to trigger wechat authorization callback and submit code for login

In addition, you can see that the user token has been successfully written to localStorage

You can search the wechat public account “Single” to experience (find bugs).

In addition, the complete project code has been hosted on Github, if necessary, you can click to view

conclusion

I have to say that Vue3 code abstraction and reuse in this piece, it is really comfortable to write, I hope you also try to follow the official practice, more decoupling logic code, generate a hook, so that the code is much more elegant. The author has tried to demonstrate this scheme, which is almost perfect both in terms of the cleanliness and elegance of the code and the realization of business requirements (please allow me to install a wave of B). Of course, there may be some bugs or pain points that I haven’t found. After all, there is no perfect architecture. We welcome all the watchers to communicate and discuss with me to provide better solutions and ideas.

Write in the last

Recently, my work is a little bit idle. I plan to use Vue3+ TS +vant to complete a public account application from 0 and share the development process, which is also a way to motivate myself to continue learning. At the same time, in order to facilitate us to better discuss the development of wechat public number related technologies, the author also built a wechat group, welcome to join us to learn and grow together.