Vue-access-control is a front-end user permission Control solution based on Vue/ VUe-Router/AXIOS. By controlling routing, view and request at three levels, developers can achieve arbitrary granularity of user permission Control.

The installation

Version for

  • Vue 2.0 x
  • Vue-router 3.x

To obtain

Project homepage: refined-x.com/Vue-Access-…

Git: git clone https://github.com/tower1229/Vue-Access-Control.git

NPM: NPM I vue-access-control

run

// run dev // build NPM buildCopy the code

An overview of the

The overall train of thought

At the beginning of the session, a Vue instance with only login route is initialized. The route is directed to the login page in the root component created hook. When the user logs in successfully, the front-end gets the user token. Configure the AXIos instance to add {“Authorization”:token} to request headers for user authentication, and then obtain the permission data of the current user, including the route permission and resource permission. Then dynamically add the route, generate the menu, and implement the permission instruction and global permission verification method. Adding a request interceptor to the AXIOS instance completes the permission control initialization. After the route is dynamically loaded, the route component is loaded and rendered, and then the front-end interface is displayed.

The created hook of the root component is responsible for checking whether there is a local token. If there is a local token, the created hook of the root component directly obtains permission and initializes the token without logging in. If the token is valid and the current route has access, The routing component is loaded and rendered correctly; If the current route does not have access, redirect 404 according to route Settings. If the token fails, the backend should return a 4XX status code, and the front-end should add an error interceptor to the AXIOS instance. When the 4XX status code is encountered, an exit operation is performed to clear the sessionStorage data and jump to the login page for the user to log in again.

Principle of least dependence

Vue-access-control positioning is a single domain solution, in addition to Vue/ VUe-Router/AXIOS without other dependencies, theoretically can be barrier-free application to any Vue project with Access Control requirements, the project is based on webpack template development and construction, Most new projects can continue development directly based on checked out code. It should be noted that the additional element-UI and CryptoJS introduced by the project are only for the development of the presentation interface. They are not required and have nothing to do with permission control.

The directory structure

/ / / SRC / | - API interface file | | - index. The js / / output common example axios | | - the js / / organization according to the business module interface file, All interface reference. / index provide instances of axios | - assets / | - components / | - the router / | | -- fullpath. Js / / complete routing data, Routing permissions have to match the user's actual routing | ` -- index. | js / / output based routing instance -- views / | - App. Vue, -- the main. JsCopy the code

Data format convention

  • The route permission data must be an object array in the following format. Two routes with the same ID and parent_ID have a superior and subordinate relationship. If you want to use the route data in a customized format, you need to modify the implementation of route control

    [{" id ":" 1 ", "name" : "menu 1", "parent_id", null, "route" : "route1"}, {" id ":" 2 ", "name" : "menu 1-1", "parent_id" : "1", "route": "route2" } ]Copy the code
  • The resource permission data must be an array of objects in the following format. Each object represents a RESTful request and supports a URL with parameters. For details about the format, see Request Control

    C9180895e172348015e1740805d000d [{" id ":" 2 ", "name" : "account - access", "url" : "/ accounts", "method" : "GET"}, {" id ": "2 c9180895e172348015e1740c30f000e", "name" : "accounts - remove", "url" : "/ account / * *", "method" : "DELETE"}]Copy the code

Routing control

Route control includes dynamic route registration and dynamic menu generation.

Dynamically Registering routes

The initial instantiated route consists of only two paths, login and 404, and we expect the complete route to look like this:

[{ path: '/login', name: 'login', component: (resolve) => require(['../views/login.vue'], resolve) }, { path: '/404', name: '404', component: (resolve) => require(['../views/common/404.vue'], resolve) }, { path: '/', name: / /views/index.vue'], resolve), children: [{path: '/route1', name: => require(['... /views/index.vue'], resolve), children: [{path: '/route1', name: => require(['... /views/index.vue'], resolve), children: [{path: '/route1', name: 'column 1', meta: {icon: 'icon-channel1'}, Component: (resolve) => require(['../views/view1.vue'], resolve)}, {path: '/route2', name: 'column 2', meta: {icon: 'ico-channel2'}, Component: (resolve) => require(['../views/view2.vue'], resolve), children: [{path: 'child2-1', name: 'child2-1', meta: { }, component: (resolve) => require(['../views/route2-1.vue'], resolve) }] }] }, { path: '*', redirect: '/404' }]Copy the code

Then the next step is to obtain the home page and its sub-routes. The idea is to store a complete route data of the whole project locally in advance, and then filter the complete route according to user permissions.

The idea of filtering is to first process the route data returned by the back end into the following hash structure:

let hashMenus = {
   "/route1":true,
   "/route1/route1-1":true,
   "/route1/route1-2":true,
   "/route2":true,
   ...
}
Copy the code

Then the local complete route is traversed, and the path is joined into the key format in the above structure in the loop. The route can be determined by using hashMenus[route]. For detailed implementation, see getRoutes() method in app.vue.

If the route permission data returned by the backend is different from the convention, you need to implement the filtering logic, as long as the actual available route data can be obtained, and finally use the addRoutes() method to dynamically add them to the routing instance. Note that the fuzzy matching of 404 pages must be placed at the end.

Dynamic menu

Routing data can be directly used to generate the navigation menu, but the routing data in the root component, navigation menu exists in the index. The vue component, obviously we need to somehow share the menu data, there are many ways, the first thought is generally Vuex, but the menu data in the process of the whole user session will not change, This is not the best use of Vuex, and in order to minimize unnecessary dependencies, the simplest and most straightforward method is to attach the menuData to the root component data.menudata and get it from the home page with this.$parent.

In addition, navigation menus may require column ICONS. This can be achieved by adding meta data to the route, such as the icon class or Unicode stored in the route meta. The meta data can be accessed in the template and used to generate icon labels.

In many roles in the system may encounter one problem is that different roles have a same name but different routing functions, such as system administrators, and the enterprise administrator has “account management” this route, but their operation permissions and target is different, in fact is two completely different interface, and the Vue does not allow multiple routing of the same name, Therefore, the name of the route must be differentiated, but it will be ugly to display the differentiated name in the front menu. To ensure that different roles can share the same menu name, we only need to set the meta. Name of the two routes to “account Management” and use meta.

See views/index.vue for details of the menu.

View control

The objective of view control is to determine whether interface elements are displayed or not according to the current user permissions. A typical scenario is display control of various operation buttons. The essence of implementing view control is to implement a permission validation method, input request permission, output approval. Then, with V-IF or JSX or custom instructions, you can flexibly implement various view controls.

Global validation method

Validation method implementation itself is very simple, no more than is given according to the backend resource permissions do judgment, the focus is on optimization method of input and output, improve ease of use, through the practice final solution is used, the power to request maintenance at the same time, the validation method receives the request object array as a parameter, whether return Boolean values with permissions.

Request object format:

Const request = {p: ['get,/accounts'], r: params => {return instance.get(' /accounts', {params})}}Copy the code

The permission validation method $_has() is called in this format:

v-if="$_has([request])"
Copy the code

See vue.prototype. $_has method in app.vue for a concrete implementation of the permission validation method.

Permissions to verify the method with global, can in the project is very easy to implement with v – if the element display control, the advantages of this approach is flexible, besides can check permissions, can also add runtime state in judging expressions do more diversity of judgment, and can take full advantage of the characteristics of v – if the response data changes, realize the dynamic view control.

For details, please refer to the relevant section of background system permission control based on Vue.

Custom instruction

V – if the response is a double-edged sword, because the judge expressions occur frequently in the operation process, but in fact his authority in a user session cycle will not change, so if you just need to check permissions, with v – if will produce a lot of unnecessary operation, this kind of situation in view when loading check it only once, This can be achieved by custom directives:

Directive ('has', {bind: function(el, binding) {if (! Vue.prototype.$_has(binding.value)) { el.parentNode.removeChild(el); }}});Copy the code

Custom directives still call global validation methods internally, but the advantage is that they are executed only once, when the element is initialized, and you should use custom directives for view control in most cases.

Request control

Request control is realized by using AXIos interceptor, which aims to intercept the unauthorized request at the front end. The principle is to judge whether the request conforms to user permissions in the request interceptor, so as to decide whether to intercept or not.

Method and request.url are consistent. Wildcard characters are required for URLS with parameters. The wildcard format needs to be agreed by the front and back ends according to project requirements. The interceptor should first process the URL with parameters into the convention format, and then determine the permission. The solution has implemented the following two wildcard formats:

/resources/:id example: /resources/1 URL: /resources/** Format: /store/:id/member Example: /store/1/member URL: /store/*/member Description: A parameter is inserted between two nouns. The parameter usually indicates the ID of the first nounCopy the code

Note that if you want to make a request with the URL “/aaa/ BBB “, it will be processed as “/aaa/**” by default for permission verification. If “BBB” is not a parameter but part of the URL, then you need to change the URL to “/aaa/ BBB /”. A “/” at the end indicates that the URL does not need to be formatted.

See the setInterceptor() method in app.vue for a detailed implementation of the interceptor.

If your project requires additional wildcard formats, just implement the corresponding detection and conversion methods in the interceptor.

Presentations and instructions

Demonstration instructions:

DEMO project demonstrates dynamic menu, dynamic routing, button permissions, request blocking.

Mock data is generated by RAP2 at the back end of the demo project. The login request should normally be in POST mode. However, because rap2 programming mode cannot obtain non-GET request parameters, only GET can be used for login.

In addition, the interface that obtains permission after login does not need to carry additional parameters. The backend can implement user authentication based on the token information carried in the request header. However, because rap2 programming mode cannot obtain headers data, only one Authorization parameter can be added to generate simulated data.

Test Account:

Username: root password: any 2. Username: client password: anyCopy the code

Demo Address:

vue-access-control.refined-x.com

Front-end road original technical article, reproduced please indicate the source: refined-x.com/2017/11/28/…

If you have any questions about the content of this article, please leave a comment or scan the qr code below to join the “Front-end road – Knowledge Planet” paid questions.