(essence) implementation of Vue Vue router dynamic routing authority control on July 14, 2020

1, addRoutes permission control

Scenario: users who have successfully logged in may have different identity permissions. The system menus and functions they see are different. At this time, dynamic routing is required

Routing structure:
|- initRoutes is the visible route by default. It is the route menu that all users can see
|- asyncRouetes routes that can only be seen after you confirm your permissions after logging in

1.1 initial route initRoutes

import Vue from "vue";
import VueRouter from "vue-router";

Vue.use(VueRouter);

import home from '../pages/home.vue';
import news from '../pages/news.vue';

var allRoutes = [{
    path:'/login',
    name:'login',
    meta:{
        title:'landing'
    },
    component:()=>import('../pages/login.vue')
},{
    path:'/home',
    name:'home',
    component:home,
    meta:{
        title:'home page'
    },
},{
    path:'/news',
    name:'news',
    meta:{
        title:'news'
    },
    component:news
}]
export default new VueRouter({
    routes:allRoutes,
    mode:'hash', //history
    base:'/',
    //   Vue router thinks that the exact active link class will be added only when the routes are truly matched,
    //   If there is only a partial overlap, active menu will be added.
    // fallback
    // Not all browsers support front-end routing. If not, set fallback: true,
    // vue will automatically fall back to hash mode.
    fallback: true,
    linkActiveClass: "active-menu",
    linkExactActiveClass: "exact-active-menu",
})
// In main JS, inject the router instance into the root instance of vue, and you can use routing

1.2 dynamic routing asyncRouetes

var asyncRouetes = [
    {
        path:'/finance',
        component:()=>import('../pages/finance.vue'),
        meta: {
            title: 'financial information ',
            roles: ['admin']
        }
       },
       {
       path:'/staffs',
       component:()=>import('../pages/staffs.vue'),
       meta: {
           title: 'Employee information',
           roles: ['admin','guest']
         }
       }
   ];

 export default  asyncRouetes;

1.3 by default, when vueRouters is instantiated, only the initial route is passed in

export default new VueRouter({
    routes:allRoutes,
    mode:'hash', //history
    base:'/',
    //   Vue router thinks that the exact active link class will be added only when the routes are truly matched,
    //   If there is only a partial overlap, active menu will be added.
    // fallback
    // Not all browsers support front-end routing. If not, set fallback: true,
    // vue will automatically fall back to hash mode.
    fallback: true,
    linkActiveClass: "active-menu",
    linkExactActiveClass: "exact-active-menu",
})
// In main JS, inject the router instance into the root instance of vue, and you can use routing
stay vue Mount when instantiating

1.4 log in and get the token and user information

 localStorage.setItem('token','XXXXXXXXXXX');
 localStorage.setItem('userRole','admin'); //submain, guest

1.5 add global routing guard

import Vue from 'vue';

import axios from './providers/axios2.js';
import api from './providers/api.js';

import App from './App.vue'
import VueRouter from './router/index.js';

//If it is global, other pages do not need to be processed, and the Babel plugin component does not need to be configured
// import ElementUI from 'element-ui';
// import 'element-ui/lib/theme-chalk/index.css';
// Vue.use(ElementUI);

Vue.prototype.$axios = axios;
Vue.prototype.$api = api;

window.EventEmitter = new Vue();

//template mode
// new Vue({
//     el:'#app',
//     data:{
//         hello:'hello',
//         msg:'world'
//     },
//     // template:`<div id="app1">
//     //     <h1>{{msg}}</h1>
//     // </div>`,
//     components:{App}, / / register global components
//     template:'<App/>'
// });
import asyncRouetes from './router/dynamic.js';
var initRoutes = VueRouter.options.routes;

//optimization
var allPaths = [];
asyncRouetes.forEach((option)=>{
    allPaths.push(option.path);
})
VueRouter.beforeEach((to, from, next) => {
    var userRole = localStorage.getItem('userRole');
    var token = localStorage.getItem('token');

     //You need to determine whether dynamic routes have been added. Do not add them repeatedly
     // Method: determine whether the default and read routes are consistent  
        var isHAS =  VueRouter.options.routes.some((option)=>{
            return allPaths.includes(option.path)
         });   
         if(isHAS){
             next();
             return;
         }
//Judge whether a token exists
    if(token && userRole){
        var asyncRouete =  asyncRouetes.filter((option,index)=>{
            return option.meta.roles.includes(userRole);
        });
        //Add a new route to the route. If the component is not added, it will not render correctly
        VueRouter.addRoutes(asyncRouete);
         //To render the navigation correctly, add the corresponding new route to the vueroouter	
        VueRouter.options.routes = [...initRoutes,...asyncRouete];
        EventEmitter.$emit('allOption',VueRouter.options.routes)
        next();
    } else {
    // Jump to landing page
        if(to.path=='/login') {
            next();
        } else {
            next('/login');
        }
    }
  
})

// render
var vm = new Vue({
    el:'#app',
    data:{
        hello:'hello',
        msg:'world'
    },
    router:VueRouter,
    // render(createElement){
    //     return createElement('div',{
    //         id:'app1'
    //     },[
    //         createElement('h1',this.msg)
    //     ])
    // },
    //Using components, rendering with render function
    // render(h){
    //      return h(App)
    // },
    render:h=>h(App)

});

2, Actual use of permission control in the project

2.1 configure necessary dynamic routing files

Add dynamic JS
Add finance Vue, staffs Vue as test

var asyncRouetes = [
    {
        path:'/finance',
        component:()=>import('../pages/finance.vue'),
        meta: {
            title: 'financial information ',
            roles: ['admin']
        }
       },
       {
       path:'/staffs',
       component:()=>import('../pages/staffs.vue'),
       meta: {
           title: 'Employee information',
           roles: ['admin','guest']
         }
       }
   ];
export default  asyncRouetes;

2.2 after successful login, you need to obtain toekn and user information

 localStorage.setItem('token','XXXXXXXXXXX');
 localStorage.setItem('userRole','admin'); //submain, guest

2.3 in the entry file main JS for navigation guard

Import file:

 import asyncRouetes from './router/dynamic.js';

Global front guard configuration:

Note: the route guard is for the vueroter instance object

 VueRouter.beforeEach((to,from,next)=>{
     //If the title is customized, take the title; otherwise, take the global title
   window.document.title = to.meta.title?to.meta.title:'Test system';

     //Here you can obtain the permission after login
     var UserToken = localStorage.getItem('token');
     var userRole = localStorage.getItem('userRole');

     //Judge whether a token exists
     if(UserToken && userRole){
         //Logged in
         var asyncRouteMenu = asyncRouetes.filter((item,index)=>{
             return item.meta.roles.includes(userRole)
         })

         //Add a new route to the route. If the component is not added, it will not render correctly
         VueRouter.addRoutes(asyncRouteMenu); 
         //To render the navigation correctly, add the corresponding new route to the vueroouter
         
         var initRoutes = VueRouter.options.routes;
         VueRouter.options.routes = [...initRoutes,...asyncRouteMenu];
         next();

     } else {
         //Whether it is on the login page
         if(to.path=='/login'){ 
             //If it is the login page path, you can directly next()
             next();
         } else {
             //Otherwise, jump to login;
             next('/login');
         }
     } 
 })

2.3 how to handle menu display

On app In Vue, the original menu

 <router-link to="/login" tag='li'>landing</router-link> 
 <router-link to="/home?name=laney" tag='li'>homepage</router-link>
 <router-link to="/news" tag='li'>news</router-link> 

It needs to be modified to be dynamic, because all the routes here are not written dead, and the routing instance this$ Router Get in options

Can be set in calculator properties

  <!DOCTYPE html>
<html lang="en">
<head>
   <meta charset="UTF-8">
   <title>Permission control- addRoutes</title>
   <link rel="stylesheet" href="css/animate.css">
   <style>
   	.active{
   		font-size:20px;
   		color:#ff7300;
   		text-decoration:none;
   	}
       .main-menu a {
           display: inline-block;
           margin-right: 10px;
       }
   </style>
   <script src="js/vue.js"></script>
   <script src="js/vue-router.js"></script>
</head>
<body>
   <div id="itapp">
   	<div class="main-menu">
           <!-- Written as dynamic -->
           <!-- $router.options.routes  From calculator properties-->
           <!-- <router-link v-for="(item,index) in $router.options.routes" :key="index" :to="item.path">{{item.meta.title}}</router-link> -->
           <router-link v-for="(item,index) in getMyRoutes" :key="index" :to="item.path">{{item.meta.title}}</router-link>
           
       </div>
   	<div>
   		<transition enter-active-class="animated bounceInLeft" leave-active-class="animated bounceOutRight">
   			<router-view></router-view>
   		</transition>
   	</div>

   	<hr>
   	<button @click="push">Add route</button>
   	<button @click="replace">Replace route</button>
   </div>

   <template id="user">
   	<div>
   		<h3>User information</h3>
   		<ul>
   			<router-link to="/user/login?name=tom&pwd=123" tag="li">User login</router-link>
               <router-link to="/user/regist/alice/456" tag="li">User registration</router-link>
   		</ul>
   		<router-view></router-view>
   	</div>
   </template>

   <script>
   	var Home={
   		template:'<h3>I am the home page</h3>'
   	}
   	var User={
   		template:'#user'
   	}
   	var Login={
   		template:'<h4>User login... Get parameters:{{$route.query}},{{$route.path}}</h4>'
   	}
   	var Regist={
   		template:'<h4>User registration... Get parameters:{{$route.params}},{{$route.path}}</h4>'
       }
       var Finance={
   		template:'<h4>financial information </h4>'
   	}
   	var News={
   		template:'<h3>I'm news</h3>'
   	}
       //The default is the visible route
   	var initRoutes=[
   		{
   			path:'/home',
   			component:Home,
   			// Routing meta information
               meta: {
                   title: 'home page'
                }
   		},
   		{
   			path:'/user',
               component:User,
               meta: {
                   title: 'user'
                },
   			// children:[
   			// 	{
   			// 		path:'login',
               //         component:Login
   			// 	},
   			// 	{
   			// 		path:'regist/:username/:password',
               //         component:Regist
               //     }

   			// ]
           },
   		// {
   		// 	path:'*',
   		// 	redirect:'/home',
           //     hidden: true / / hide routes that do not need to be rendered to the page
   		// }
   	];

   	 //Routes that can only be seen after you confirm your permissions after logging in
   	 var asyncRouetes = [
        {
            path:'/finance',
            component:Finance,
             meta: {
                title: 'financial information ',
                roles: ['admin']
            }
   		},
   		{
           path:'/news',
           component:News,
           meta: {
               title: 'Press Center',
               roles: ['admin','guest']
             }
           }
       ];
   	const routerAll=new VueRouter({
   		routes:initRoutes, //Short for routes:routes
   		linkActiveClass:'active', //Update the class name of the active link. The default active class
   		linkExactActiveClass:'active-extact',  //Precisely activated class
   		mode: "hash", //default
   	});

   	////Navigation guard
   	//Joined you to get the role
   	routerAll.beforeEach((to, from, next) => {
   		// var auth = localStorage.getItem('userRole');
   		var auth = 'admin';
   		var asyncRouete =  asyncRouetes.filter((option,index)=>{
   			return option.meta.roles.includes(auth);
   		});
   		//Add a new route to the route. If the component is not added, it will not render correctly
   		routerAll.addRoutes(asyncRouete);
   		 //To render the navigation correctly, add the corresponding new route to routerAll	
   		routerAll.options.routes = [...initRoutes,...asyncRouete];
   		debugger
   		next();
   	})
   
   	new Vue({
           el:'#itapp',
   		router:routerAll, //Injection routing
           computed:{
               getMyRoutes(){
                   var thisData = this.$router.options.routes;
                   return thisData;
               }
           },
   		methods:{
   			push(){
   				this.$router.push({path:'home'}); //Add route, switch route	
   			},
   			replace(){
   				routerAll.replace({path:'user'}); //Replace route, no history
   			}
           }
          
          
   	});
   </script>
</body>
</html>

Use the central control vue instance and eventEmitter

  <template>
     <div id="app">
        <h1>{{msg}} <button type="button" @click="logOut()">logout</button></h1>
        <div >
            <ul class="main-menu">
             <router-link v-for="(item,index) in getMyRoutes" :key="index" :to="item.path" tag='li'>{{item.meta.title}}</router-link> 
                <!-- <router-link to="/login" tag='li'>landing</router-link> 
                <router-link to="/home?name=laney" tag='li'>homepage</router-link>
                <router-link to="/news" tag='li'>news</router-link>  -->
            </ul>
        <!-- <ul @click="gotoPage($event)">
            <li tag='home'>homepage</li>
            <li tag='news'>news</li>
        </ul>    -->
        </div>
        <router-view></router-view>
    </div>
</template>

 <script>
    export default {
        name: 'app',
        data () {
            return {
                msg: 'Welcome to ruanmou',
                getMyRoutes:[]
            }
        },
        computed:{
            // getMyRoutes(){
            //     console.log('this.$router.options.routes')
            //     console.log(this.$router.options.routes)
            //     var thisData = this.$router.options.routes;
            //     return thisData;
            // }
        },
        methods:{
             logOut(){
                localStorage.clear();
                this.$router.push({
                    path:'/login'
                })
                location.reload();
              },
            gotoPage(ev){
                var target = ev.target,
                    tag = target.getAttribute('tag');
                switch(tag){
                    case 'home':
                        //Equivalent to get mode
                        this.$router.push({
                            path:'/home',
                            query:{
                                name:'laney'
                            }
                        })
                    break;
                    case 'news':
                        this.$router.push({
                            path:'/news',
                            query:{
                                age:'10'
                            }
                        })
                    break;
                }
                }
        },
        mounted(){  
            EventEmitter.$on('allOption',(res)=>{
                console.log('mounted')
                console.log(res)
                this.getMyRoutes = res;
            })
            console.log(this.$router.options.routes)
        }
    }
</script>

<style scoped>
.main-menu li {
    display: inline-block;
    margin-right: 30px;
    background: #000;
    color: #fff;
    padding: 5px 20px;
    cursor: pointer;
}
.main-menu li.active-menu{
    background: #ff6600;
    
}
</style>

Tags: Vue

Posted by jaypotter on Tue, 31 May 2022 07:28:06 +0530