Hand touch, take you with Vue Backstage Series II (Login permission chapter)

Source: Internet
Author: User
Tags commit require touch blank page

Full Project Address: Vue-element-admin
Department Article one: Hand touch hand, take you with Vue Backstage series one (basic article)
Department Article three: Hand touch hand, take you with Vue back Backstage series three (actual combat article)
Department article four: Hand touch, take you with Vue Backstage series four (vueadmin a minimalist background basic template) preface

Drag a bit more serious, after half a month to write a second tutorial. Helpless oneself is a business ape, every day by our products abuse of the dead, and then sick a bit of rest for a few days, we forgive.

To get to the point, do the background project is different from doing other projects, authorization verification and security is very important, can be said to be a background project at the outset must consider and build the core functions of the foundation. What we want to do is: different permissions correspond to different routes, and the sidebar also needs to be generated asynchronously according to different permissions. Here first of all, I implement login and authorization to verify the idea.

Login: When the user completed the account and password to the server to verify the correct, after the verification, the server will return a token, after the token (I will store this token in a cookie, to ensure that the page can remember the user login status), The front end will pull a User_info interface based on token to get the user's details (such as user rights, user name, etc.).

Permission verification: Through token to obtain the role of the user, dynamically according to the user's role to calculate its corresponding privileged route, through router.addroutes dynamic mount routing.

All of the above data and operations are controlled by VUEX global management. Next, we hand-touch the hand to achieve this system step-by-step. sign-in article

First of all, we don't care what permissions, to achieve the most basic login function.

Just find a blank page. Two boxes of input, one is login account, one is login password. Then place a login button. We bind the login button to the Click event and click Login to submit an account and password to the server for verification.
This is one of the simplest login pages. If you feel you need to write more perfectly, you can make a simple check on your account and password before submitting it to the server. Detailed code

Click event Triggers login action

this. $store. Dispatch (' Loginbyemail ', this.loginform). then (() = {this
  . $router. Push ({path: '/'});// Redirect to Home} after successful login
). catch (Err = {this
  . $message. Error (ERR);//Login failed prompt
});

Action

Loginbyemail ({commit}, UserInfo) {
  Const email = userInfo.email.trim ();
  return new Promise ((resolve, reject) = {
    Loginbyemail (email, userinfo.password). Then (response = {
      const data = Response.data;
      Cookies.set (' Token ', response.data.token); After successful login, store tokens in Cookie
      commit (' Set_token ', data.token);
      Commit (' Set_email ', EMAIL);
      Resolve ();
    }). catch (Error = {
      reject (error);});}
  );

After the login is successful, the server returns a token (which is a key that uniquely identifies the user), then we store the token in a local cookie so that the next time the page is opened or the page is refreshed, the user's login will be remembered. No more logging in to the login page.

PS: In order to ensure security, I am now in the background all token validity period (expires/max-age) is the session, that is, when the browser is closed and lost. Re-open the browser will require re-login verification, the backend will also be fixed at a weekly point in time to re-refresh token, let the background users all re-login, to ensure that the background users will not be lost because of the computer or other reasons people are free to use the account. Get user Information

After the user login is successful, we intercept the route in the global hook Router.beforeeach to determine if the token has been obtained and we will get the basic information of the user after we get token.

Router.beforeeach
if (store.getters.roles.length = = = 0) {//Determines whether the current user has pulled out user_info information
  store.dispatch (' GetInfo '). Then (res = {//pull user_info
    const roles = Res.data.role;
    Next ();//resolve Hooks
  })

As I said earlier, I only store a user token locally and do not store other user information (such as user rights, user names, etc.). Some people ask why not save some other user information. Mainly for the following considerations:
Suppose I have the user rights and names also exist locally, but I use another computer to log in to modify their user name, and then use the computer with the previous user information to log on, it will default to read the name of the local cookie, and will not remove the new user information. So now the strategy is that the page will first check from the cookie whether there is a token, no, go through the previous part of the process of re-login, if there is token, will go to pull user_info, to ensure that the user information is up-to-date.
Of course, if you do a single sign-on function, the user information stored locally is also possible. But when you log in one computer, the other one will be posted offline, so always log back in to get the latest content.

But from the code level I suggest or the login and get_user_info two things separate better, in this back end of the full micro-service era, back-end students also want to write elegant code ~ Permission Chapter

First of all, let's talk about the main idea of my authority control, the front end will have a routing table that represents the permissions that each route can access. When the user logs in, the user's role is obtained through token, dynamically according to the user's role to calculate the corresponding permissions of the route, and then through the router.addroutes dynamic mount routing. However, these controls are only page-level, the front-end how to do permissions control is not absolutely safe, back-end authorization is not escaped.
Division I is now the front-end to control the page-level permissions, different permissions of the user display different sidebar and can enter a different page (also do a little button level of permission control), the back end will verify each operation involved in the request, verify that it has permission to the operation, Every request in the background, whether get or post, will have the front end carry the user's token inside the request header, and the backend will verify that the user has permission to perform the operation based on that token. The right front end or back end to control.

There are a lot of people who say that their company's routing table is generated dynamically based on the user's rights, and we don't take this approach for the following reasons:

Project iteration you will be very painful, the front-end of a new development of a page also to let the backend with the routing and permissions, let us think of the previous and the end of the non-separation, the back end of the time dominated the terror.

Secondly, take our business, although the backend does have the authority to verify, but it is the verification of the business to be divided, such as super-editor can publish articles, and internship editing can only edit the article can not be published, but for the front-end, whether it is super-editing or internship editing is the right to enter the article editing page. So the partitioning of front-end and back-end permissions is less consistent.

One more thing is that it's a hassle to mount a route asynchronously before vue2.2.0. But fortunately, the official also out of the new API, although the intention is to solve the SSR pain points ... addroutes

It is difficult to do this before dynamically returning front-end routing through the backend, because the vue-router must be mounted on the Vue before it is instantiated, and it is not convenient to change dynamically. But fortunately, after vue2.2.0 new router.addroutes

Dynamically add routes to the router. The argument must is an Array using the-same route config format with the routes constructor option.

With this we can be relatively convenient to do permission control. (Landlord before the authority control also walked a lot of fruitless, can be seen in the project commit record, refactoring many times, the earliest useless addroute the entire authority control code are all kinds of if/else logic judgment, the code is quite coupled and complex) Specific Implementation

1. When creating the Vue instance, mount the Vue-router, but this time vue-router mount some of the common pages that are logged in or do not have permissions.
2. When the user logs in, gets the role, compares the required permissions for each page of the role and the routing table, and generates a routing table that the end user can access.
3. Call Router.addroutes (store.getters.addRouters) to add a route that the user can access.
4. Use Vuex to manage the routing table to render the sidebar component based on the routes accessible in Vuex. Router.js

First we implement the Router.js routing table, here take the front-end control Road Origin example (the back end of the same, a little transformation is good)

Router.js import vue from ' Vue ';

Import Router from ' Vue-router '; Import Login from '.
/views/login/'; Const DASHBOARD = Resolve = require ([' ...
/views/dashboard/index '], resolve); Use Vue-routerd's [Lazy Loading Routes] (https://router.vuejs.org/en/advanced/lazy-loading.html)//All Rights universal routing Table// such as the homepage and landing page and some public pages without permission to export const CONSTANTROUTERMAP = [{path: '/login ', Component:login, hidden:true//hidden for custom attributes, side Sidebar that chapter will be slender explanation}, {path: '/', component:layout, redirect: '/dashboard ', Name: ' Home ', children: [{path: ' Dashboard ', Component:dashboard}]},]//When instantiating Vue only Mount Constantrouter export default new Router ({Routes:constantrou

Termap}); Async-Mounted routing//dynamic requires a routing table loaded according to permissions export const ASYNCROUTERMAP = [{path: '/permission ', Component:layout, Redire 
        CT: '/permission/index ', Name: ' Permission Test ', Meta: {role: [' admin ', ' super_editor '},//page requires permission children: [{
  Path: ' Index ', component:permission, Name: ' Permissions test Page ',      Meta: {role: [' admin ', ' super_editor '}//page required permissions}]}, {path: ' * ', redirect: '/404 ', hidden:true}];
 

Here we use META tags to indicate which permissions are available to the page according to Vue-router's official recommendation. such as meta: {role: [' admin ', ' Super_editor '}} indicates that the page is eligible for access only by admin and Super Editor.
Note: Here is a need to pay great attention to the place is the 404 page must be last loaded, if put in Constantroutermap together declared 404, after the page will be intercepted to 404, detailed problems see addroutes when you ' ve got a Wildcard route for 404s does isn't work main.js

The key main.js

Main.js Router.beforeeach (to, from, next) = {if (Store.getters.token) {//Determines if there is a token if (To.path = = = '/log
    In ') {Next ({path: '/'}); } else {if (store.getters.roles.length = = 0) {//Determines whether the current user has pulled out user_info information store.dispatch (' GetInfo '). Then (r
          Es = = {//pull info Const roles = Res.data.role; Store.dispatch (' Generateroutes ', {roles}). then (() = {//Generate accessible routing table router.addroutes (Store.getters.addRou ters)//Dynamically add accessible routing table next (To.path);
        Hack method to ensure addroutes completed}). catch (Err = {Console.log (err);
      }); } else {next ()//when there is a user right, it is stated that all accessible routes have been generated, such as access without permission, to fully automatically enter the 404 Page}}} else {if (Whitelist.indexof (to
    . Path)!==-1) {//On white list without login, go directly to next (); } else {next ('/login ');//redirect all to the login page}}});

The Router.beforeeach here also combines some of the login logic code in the previous chapter.


The above picture is in the use of the Addroutes method before the permission to judge, very cumbersome, because I have all the routes are hanging up, all I want to determine whether the current user has access to the page, a variety of if/else nesting, maintenance is quite difficult. But now with the addroutes is very convenient, I only mount the user has access to the page, no permissions, the route automatically help me jump 404, save a lot of judgment.

There is also a small hack place, that is, after the Router.addroutes next () may fail, because the next () may be when the route is not complete add, good to see the document found

Next ('/') or next ({path: '/'}): Redirect to a different location. The current navigation would be aborted and a new one would be started.

This way we can easily avoid the previous problem by simply using next. Store/permission.js

Let's just talk about Generateroutes Action.

Store/permission.js Import {asyncroutermap, constantroutermap} from ' Src/router '; function haspermission (roles, route) {if (Route.meta && route.meta.role) {return roles.some (role = Rou Te.meta.role.indexOf (role) >= 0)} else {return true}} Const Permission = {state: {Routers:constan Troutermap, Addrouters: []}, mutations: {set_routers: (state, routers) = {State.addrouters = rout
      ERs
    State.routers = Constantroutermap.concat (routers); }}, Actions: {generateroutes ({commit}, data) {return new Promise (resolve = = {const {roles
        } = data;
          Const Accessedrouters = Asyncroutermap.filter (v = = {if (roles.indexof (' admin ') >= 0) return true; if (haspermission (roles, V)) {if (V.children && v.children.length > 0) {v.child
        ren = v.children.filter (Child = {if (haspermission (roles, child)) {          Return child} return false;
              });
        Return v} else {return v}} return false;
        });
        Commit (' set_routers ', accessedrouters);
      Resolve ();

})
    }
  }
};
 Export default permission;

The code here is a matter of doing, through the user's permissions and before the router.js inside the asyncroutermap of each page required to make a match, and finally return to a user who can access the route. Side Bar

The last place to relate to permissions is the sidebar, but on the basis of the previous is very convenient to realize the dynamic display side bar. The sidebar here is based on the Element-ui Navmenu.

<template>
    <el-menu:unique-opened= ' true ' mode= "vertical" theme= "dark":d efault-active= "$route. Path" >
        <template v-for= "item in Permission_routers" v-if= "!item.hidden" >
            <el-submenu:index= " Item.name "v-if="!item.nodropdown ">
                <template slot=" title ">
                    <wscn-icon-svg:icon-class=" item.icon| | ' Wenzhang1 ' "/> {{item.name}}
                </template>
                <router-link v-for=" Child in Item.children "<

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.