In the interaction process of front and background, the user login permission and front-end routing module are relatively complex modules, so we need to clarify the whole process to put up the whole engineering architecture. In fact, in my previous article (juejin.cn/post/698328… This process is discussed in general in the. Now I’m going to tease it out with specific front and back end project examples in order to see the whole process at once. This article focuses on the example project to explain how the entire login and front-end routing control permissions are done.

1. Implement front-end and back-end login authentication

In this paper, the front and back end login verification is realized through token authentication mechanism. The background framework based on Koa 2.0 will generate token after successful login, and the client will get and save the generated token. In the next request, the token will be automatically carried in the request header. Authentication is performed on the server side (JWT signature authentication is used in this article to verify the identity information of the front and back ends).

users.post('/login'.async (ctx, next) => {
  const { name, password } = ctx.request.body;
  const validate = Validate.loginCheck({ name, password });
  if (validate) {
    ctx.throw(400.'Parameter error! ');
  }
  const sqlData = await model.findUserData(name, password);  // Check whether the user exists
  if (sqlData && sqlData.length > 0) {
    // Obtain the token value after login
    const userId = sqlData[0].userId;
    const token = jwtService.sign({
      userId
    });
    ctx.body = { code: 200.data: token };
  } else {
    ctx.throw(400.'Wrong login account or password! '); }})Copy the code

The code above, log in successfully generated when JWT signed token (through jwtService. Js file encapsulation sign method implementation), then the current client signature verification token to carry back how to do? The general method is to use the background local cache token, and then verify with the token brought from the front end (through the verify method encapsulated in the jwtService.js file). In this paper, we do not need the background local cache token, but through signature verification:

/** * Returns the current user information */
users.post('/checkToken'.async (ctx, next) => {
  const { token } = ctx.request.body;
  if(! token) { ctx.throw(401."Please log in first.");
  }
  let data = jwtService.verify(token);   // Authenticate the current user with the obtained token information
  if(! data || ! data.userId) { ctx.throw(401."Token has expired, please log in again");
  }
  const sqlData = await model.findUserById(data.userId);  // Check whether the user exists
  const userList = {
    roles: [sqlData[0].roles],
    name: sqlData[0].name,
    avatar: sqlData[0].avatar
  }
  ctx.body = {
    code: 200.data: {
      userList
    }
  }
})
Copy the code
// Code file jwtservice.js
const jwt = require("jsonwebtoken");
const processEnv = process.env; 
const JWT_SECRET = processEnv.JWT_SECRET || "n9r5tiv5";
module.exports = {
    /** * Get JWT token *@param data
     * @returns {*}* /
    sign(data) {
      let config = 24 * 3600;
      let token = jwt.sign(
        {
          exp:
            Math.floor(Date.now() / 1000) + config ,
          data: data
        },
        JWT_SECRET
      );
      return token;
    },
    /** * validates the token, returns either null or validates the token@param token
     * @returns {data | null}* /
    verify(token) {
      try {
        let decode = jwt.verify(token, JWT_SECRET);
        return decode.data;
      } catch (err) {
        // Do not process err
        return null; }}};Copy the code

2. Control front-end route permission

Let’s simply analyze the system routing permission logic:

  1. We distinguish routing objects by whether they have permissions or notNon-permission routing objectandPermission routing object. When initialized, willNon-permission routing objectAssign to the Router and setPermissions routingFor example, meta:{roles:[‘admin’,’ Editor ‘]} specifies the routing permission for roles.
  2. Routes are matched and new route objects are generated based on the roles value returned after successful login.
  3. When the user successfully logs in and jumps to the home page, the menu on the left is rendered according to the route object just generated. Different users see different menus.

Based on the implementation of login authentication at the front and back ends above, we analyze the logic of user login page and exit page in combination with the permission of route control. This process is mainly completed in the stage of route guard, that is, the next jump logic is determined by the route navigation hook router.beforeeach () function:

  • If the user does not log in, the system initialization page is displayed. Enter the user name and password to log in.
  • If the user has logged in successfully and obtained the token value, go to the login page if the user accesses the login page. If a user accesses a non-login page, perform different service logic based on whether the user has roles information cached:

(1) Roles information is null in the initial case:

1. Use the sysGetUserInfo() function to pull the user information based on the token. Information about the user roles and name is stored in VUEX through store. 2. Run store.dispatch('GenerateRoutes', {roles}) to re-filter and generate permission routes for the current user role, and run router.addroutes () to merge routing tables. 3. If an error occurs while obtaining user information, login to the login page by invoking the store.dispatch('LogOut') interface.Copy the code

(2) The user already has roles information:

1. Click the route page and check hasPermission() based on roles permission. If the user has the route permission, the user can directly go to the corresponding page. If you do not have the permission, go to the 401 prompt page.Copy the code

The implementation code of the core logic is as follows:

/** * Check whether the current route forward permission *@param {*} roles 
 * @param {*} permissionRoles 
 * @returns * /
function hasPermission(roles, permissionRoles) {
  if (roles.indexOf('admin') > =0) return true 
  if(! permissionRoles)return true
  return roles.some(role= > permissionRoles.indexOf(role) >= 0)
}

router.beforeEach((to, from, next) = > {
  console.log('Route guard', to);
  NProgress.start()  // Displays a progress bar at the top of the page
   // Set the browser header title
   const browserHeaderTitle = to.meta.title
   store.commit('SET_BROWSERHEADERTITLE', {
     browserHeaderTitle: browserHeaderTitle
   })
  // When you click login, you get the token and save the cookie to ensure that you can always get the token when the page is refreshed
  if (getToken('Token')) {
    if(to.path === '/login') {
      next({ path: '/' })  
      NProgress.done() 
    } else {
      // After the user logs in successfully, every time the user clicks the route, the user determines the role;
      if (store.getters.roles.length === 0) {
        let token = getToken('Token');
        sysGetUserInfo({"token": token}).then().then(res= > { // Pull user information based on the token
          let userList = res.data.userList;
          store.commit("SET_ROLES",userList.roles);
          store.commit("SET_NAME",userList.name);
          store.commit("SET_AVATAR",userList.avatar);
          // Create a routing table by retrieving the current user's permission information:
          store.dispatch('GenerateRoutes', { "roles":userList.roles }).then(() = > { // Generate an accessible routing table based on roles permissions
            router.addRoutes(store.getters.addRouters) // Dynamically add access routing tablenext({ ... to,replace: true }) // The hack method ensures that addRoutes is complete
          })
        }).catch((err) = > {
          store.dispatch('LogOut').then(() = > {
            Message.error(err || 'Verification failed, please login again')
            next({ path: '/'})})})}else {
        // If there is no need to dynamically change permissions, you can directly next() delete the lower permissions ↓
        if (hasPermission(store.getters.roles, to.meta.roles)) {
          next()//
        } else {
          next({ path: '/ 401'.replace: true.query: { noGoBack: true}})}}}}else {
    // No token is obtained and the route is /login
    if (['/login'].indexOf(to.path) ! = = -1) {
      next()
    } else {
      next('/login')
      NProgress.done()
    }
  }
})
Copy the code

Before and after this article source:

  • Front-end Github address: github.com/llz1990/llz…
  • Back-end Github address: github.com/llz1990/llz…