Vue2.0 user permission control solution, vue2.0 permission Control
Vue-Access-Control is a front-end user permission Control solution based on Vue, Vue-Router, and axios. It controls the routing, view, and request layers, this allows developers to implement user permission control at any granularity.
Install
Version requirements
Vue 2.0x
Vue-router 3.x
Obtain
Git: git clone https://github.com/tower1229/Vue-Access-Control.git
Npm: npm I vue-access-control
Run
// Develop npm run dev // build npm build
Overview
Overall Thinking
At the beginning of the session, initialize a Vue instance with only the logon route. In the root component created hook, direct the route to the logon page. After the user successfully logs on, the frontend receives the User token, set the axios instance to add {"Authorization": token} to the request headers for user authentication. Then, obtain the permission data of the current user, including the routing permission and resource permission, and then add the route dynamically, generate a menu to implement permission commands and global permission verification methods, and add request interceptors to the axios instance. At this point, permission control Initialization is complete. After a route is dynamically loaded, the routing component is loaded and rendered, and the front-end interface is displayed.
To solve the problem of refresh the route reset by the browser, save the token to sessionStorage after obtaining the token. The created hook of the root component is responsible for checking whether the local token already exists, if yes, you do not need to log on and directly use the token to obtain the permission and initialize it. If the token is valid and the current route has the permission to access it, the route component is loaded and displayed correctly; if the current route has no access permission, the route will jump to 404 according to the route settings. If the token is invalid, the backend should return a 4xx status code. The front end should add an error Interceptor to the axios instance. In the event of a 4xx status code, the system will exit, clear sessionStorage data and go to the logon page to allow users to log on again.
Minimum dependency Principle
Vue-Access-Control is a single-domain solution with no dependencies other than Vue, Vue-Router, and axios, theoretically, it can be easily applied to any Vue project with permission control requirements. The project is developed and built based on the webpack template, and most new projects can be directly developed based on the detection code. It should be noted that the Element-UI and CryptoJS introduced by the project are only used for the Development demonstration interface. They are not required and have no relationship with permission control. You can choose between them in the project application.
Directory structure
Src/| -- api // interface file | -- index. js // output a general axios instance | -- account. js // interface file organized by business module. All interfaces are referenced. /The axios instance provided by index | -- assets/| -- components/| -- router/| -- fullpath. js // complete route data, used to match the user's route permissions to obtain the actual route | '-- index. js // output basic route instance | -- views/| -- App. vue · -- main. js
Data format conventions
Route permission data must be an array of objects in the following format. The two routes with the same id and parent_id have a parent-child relationship. To use custom format route data, you must 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"}]
Resource permission data must be an array of objects in the following format. Each object represents a RESTful request and supports url with parameters.
[{"Id": "2c9180895e172348015e1740805d000d", "name": "account-GET", "url": "/accounts", "method": "GET "}, {"id": "2c9180895e172348015e1740c30f000e", "name": "account-DELETE", "url": "/account/**", "method": "DELETE"}]
Route Control
Route Control consists of Dynamic Registration of routes and dynamic generation menu.
Dynamic Route Registration
The originally instantiated route only contains two paths: logon and 404. We expect the complete route to be like this:
[{Path: '/login', name: 'login', component: (resolve) => require (['.. /views/login. vue '], resolve)}, {path:'/100', name: '000000', component: (resolve) => require (['.. /views/common/404. vue '], resolve)}, {path:'/', name: 'homepage', component: (resolve) => 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: 'subtopic 2-1', meta: {}, component: (resolve) => require (['.. /views/route2-1.vue '], resolve)}]}, {path:' * ', redirect:'/100'}]
Next, you need to obtain the home page and its sub-routes. The idea is to save a copy of the complete route data of the entire project locally, and then filter the complete route according to the user permission.
The implementation idea of filtering is to first process the routes returned by the backend into the following hash structure:
let hashMenus = { "/route1":true, "/route1/route1-1":true, "/route1/route1-2":true, "/route2":true, ...}
Then, traverse the local complete route and concatenate the path into the key format in the above structure in a loop. Through hashMenus [route], you can determine whether the route matches. For details, see App. the getRoutes () method in the vue file.
If the routing permission data returned by the backend is different from the conventions, You need to implement the filtering logic on your own, as long as you can obtain the actual available routing data, and finally use addRoutes () method to dynamically add them to the routing instance. Note that the fuzzy match of 404 page must be placed at the end.
Dynamic menu
The route data can be directly used to generate navigation menus, but the route data is obtained from the root component. The navigation menu exists in index. in the vue component, we obviously need to share menu data in some way. There are many methods. Generally, the first thing we think of is Vuex, but the menu data will not change throughout the user session, this is not the best use case of Vuex, and in order to minimize unnecessary dependencies, the simplest and most direct method is used here to link the menu data to the root component data. on menuData, use this on the home page. $ parent. obtain menuData.
In addition, you may need to add column icons in the navigation menu, which can be achieved by adding meta data to the route, such as saving the icon class or unicode to the route meta, meta data can be accessed in the template to generate icon labels.
One problem that may occur in a multi-role system is that different roles have a route with the same name but different functions. For example, both the system administrator and the enterprise administrator have the "Account Management" route, however, their operation permissions and objectives are different. In fact, there are two completely different interfaces, and Vue does not allow many routes with the same name. Therefore, the routing name must be differentiated, however, displaying the differentiated name on the front-end menu is not beautiful. To enable different roles to enjoy the same menu name, we only need to set the meta of the two routes. set the name to "Account Management". meta is preferred in template loop. name.
For more information about menu implementation, see views/index. vue.
View Control
The purpose of View control is to determine whether to display the interface elements based on the current user permissions. A typical scenario is to control the display of various operation buttons. The essence of implementing view control is to implement a permission verification method, input the request permission, and output whether the permission is granted. Then, you can use the v-if, jsx, or custom commands to flexibly implement various view controls.
Global verification method
The implementation of the verification method is very simple. It is simply based on the resource permissions provided by the backend. The key is to optimize the input and output of the method to improve ease of use, maintain permissions and requests at the same time, verify that the array of request objects received by the method is a parameter, and return a Boolean value that has permissions.
Request object format:
// Obtain the account list const request = {p: ['get,/accounts'], r: params => {return instance. get ('/accounts', {params })}}
Call format of the permission verification method $ _ has:
v-if="$_has([request])"
For details about how to implement the permission verification method, see vue. prototype. $ _ has in App. Vue.
By adding the permission verification method globally, you can easily implement element display control with v-if in the project. This method has the advantages of flexibility, in addition to permission verification, you can also add runtime states to the judgment Expression for more diversified judgment, and make full use of the characteristics of v-if response data changes to achieve dynamic view control.
For detailed implementation details, refer to the relevant chapter in implementing backend system permission Control Based on Vue.
Custom commands
The response feature of v-if is a double-edged sword, because the judgment Expression is frequently triggered during the running process, but in fact its permissions will not change during a user session period, therefore, if you only need to verify the permission, using v-if will generate a large number of unnecessary operations. In this case, you only need to verify the view once when loading. You can use custom commands to achieve this:
// Permission command Vue. directive ('has', {bind: function (el, binding) {if (! Vue. prototype. $ _ has (binding. value) {el. parentNode. removeChild (el );}}});
The custom command still calls the global verification method, but the advantage is that it will only be executed once during element initialization. In most cases, you should use custom commands for view control.
Request control
Request control is implemented using the axios Interceptor to intercept unauthorized requests on the front end. The principle is to determine whether the request meets the user permission in the request interceptor to determine whether to intercept the request.
It is easy to determine a common request. You can traverse the resource permission format returned by the backend and directly determine the request. method and request. if the url matches, you can use wildcards for URLs with parameters. Here, you need to negotiate with each other based on the project requirements. After specifying the wildcard format, in the interceptor, you must first process the url with parameters into the agreed format and then judge the permission. The following two wildcard formats have been implemented in the scheme:
1. format:/resources/: id Example:/resources/1 url:/resources/** explanation: A noun is followed by a parameter, which usually represents the id of a noun 2. format:/store/: id/member example:/store/1/member url:/store/*/member explanation: a parameter is included between two nouns, the parameter usually indicates the id of the first noun.
Note that if you want to initiate a request with a url of "/aaa/bbb, by default, it is processed as "/aaa/**" for permission verification. If "bbb" is not a parameter but a part of the url, then you need to change the url to "/aaa/bbb/" and add "/" at the end to indicate that the url does not need to be converted.
For the specific implementation of the interceptor, see the setInterceptor () method in App. vue.
If your project requires other wildcard formats, you only need to implement the corresponding detection and conversion methods in the interceptor.
Demo and description
Demo description:
The DEMO project demonstrates dynamic menus, dynamic routing, button permissions, and request interception.
The mock data is generated by rap2 at the backend of the demo project. The login request is usually POST, but the non-GET request parameters cannot be obtained in rap2 programming mode. Therefore, you can only log on using GET, we do not recommend that you follow these steps in your project;
In addition, the interface for obtaining permissions after logon does not need to carry additional parameters. the backend can implement User Authentication Based on the token information carried by the request header, but the headers data cannot be obtained in rap2 programming mode, therefore, only one "Authorization" parameter can be added to generate analog data.
Test account:
1. username: root password: Any 2. username: client password: Any