Vue 开发实战实战篇 # 32:如何使用路由管理用户权限

Posted 凯小默

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Vue 开发实战实战篇 # 32:如何使用路由管理用户权限相关的知识,希望对你有一定的参考价值。

说明

【Vue 开发实战】学习笔记。

效果

访问没有权限的路由跳转到403页面

菜单也是根据权限进行展示,比如是user用户没有表单的权限访问

auth.js 权限校验文件

export function getCurrentAuthority() 
    return ["user"];


export function check(authority) 
    const current = getCurrentAuthority();
    return current.some(item => authority.includes(item));


export function isLogin() 
    const current = getCurrentAuthority();
    return current && current[0] !== "guest";

403 页面

<template>
    <div>403页面</div>
</template>

<script>
export default ;
</script>

<style></style>

路由配置页面

import Vue from "vue";
import VueRouter from "vue-router";
import NProgress from "nprogress";
import "nprogress/nprogress.css";
import  notification  from "ant-design-vue";
import NotFound from "../views/404";
import Forbidden from "../views/403";
import findLast from "lodash/findLast";
import  check, isLogin  from "../utils/auth";

Vue.use(VueRouter);

const routes = [
	
		path: "/user",
        hideInMenu: true,
		component: () =>
			import(/* webpackChunkName: "layout" */ "../layouts/UserLayout"),
		children: [
			
				path: "/user",
				redirect: "/user/login"
			,
			
				path: "/user/login",
				name: "login",
				component: () =>
					import(/* webpackChunkName: "user" */ "../views/User/Login"),
			,
			
				path: "/user/register",
				name: "register",
				component: () =>
					import(/* webpackChunkName: "user" */ "../views/User/Register"),
			
		],
	,
	
		path: "/",
        meta:  authority: ["user", "admin"],
		component: () =>
			import(/* webpackChunkName: "layout" */ "../layouts/BasicLayout"),
		children: [
			
				path: "/",
				redirect: "/dashboard"
			,
			
				path: "/dashboard",
				redirect: "/dashboard/analysis"
			,
			
				path: "/dashboard",
				name: "dashboard",
                meta:  icon: "dashboard", title: "仪表盘" ,
				component:  render: h => h("router-view"),
				children: [
					
						path: "/dashboard/analysis",
						name: "analysis",
                        meta:  title: "分析页" ,
						component: () =>
							import(/* webpackChunkName: "dashboard" */ "../views/Dashboard/Analysis"),
					,
				]
			,
			
				path: "/form",
				name: "form",
                meta:  icon: "form", title: "表单", authority: ["admin"] ,
				component:  render: h => h("router-view"),
				children: [
					
						path: "/form",
						redirect: "/form/basic-form"
					,
					
						path: "/form/basic-form",
						name: "basicform",
                        meta:  title: "基础表单" ,
						component: () =>
							import(/* webpackChunkName: "form" */ "../views/Forms/BasicForm"),
					,
					
						path: "/form/step-form",
						name: "stepform",
                        hideChildrenInMenu: true,
                        meta:  title: "分步表单" ,
                        component: () =>
							import(/* webpackChunkName: "form" */ "../views/Forms/StepForm"),
						children: [
							
								path: "/form/step-form",
								redirect: "/form/step-form/info"
							,
							
								path: "/form/step-form/info",
								name: "info",
								component: () =>
									import(/* webpackChunkName: "form" */ "../views/Forms/StepForm/Step1"),
							,
							
								path: "/form/step-form/confirm",
								name: "confirm",
								component: () =>
									import(/* webpackChunkName: "form" */ "../views/Forms/StepForm/Step2"),
							,
							
								path: "/form/step-form/result",
								name: "result",
								component: () =>
									import(/* webpackChunkName: "form" */ "../views/Forms/StepForm/Step3"),
							,
						]
					,
				]
			
		],
	,
	
		path: "/403",
		name: "403",
        hideInMenu: true,
		component: Forbidden
	,
	
		path: "*",
		name: "404",
        hideInMenu: true,
		component: NotFound
	
];

const router = new VueRouter(
	mode: "history",
	base: process.env.BASE_URL,
	routes
);

// 路由守卫
router.beforeEach((to, from, next) => 
    if(to.path !== from.path) 
	    NProgress.start();
    
    // 找到最近匹配的那个
    const record = findLast(to.matched, record => record.meta.authority);
    if(record && !check(record.meta.authority)) 
        if(!isLogin() && to.path !== "/user/login") 
            next(
                path: "/user/login"
            );
        else if(to.path !== "/403")
            notification.error(
                message: "403",
                description: "你没有权限访问,请联系管理员"
            );
            next(
                path: "/403"
            );
        
	    NProgress.done();
    
	next();
)

router.afterEach((to, from) => 
	NProgress.done();
)

export default router;

侧边栏权限 SiderMenu.vue

<template>
    <div style="width: 256px">
        <a-menu
            :selectedKeys="selectedKeys"
            :openKeys.sync="openKeys"
            mode="inline"
            :theme="theme"
        >
            <template v-for="item in menuData">
                <a-menu-item v-if="!item.children"
                    :key="item.path"
                    @click="() => $router.push(path: item.path, query: $router.query)"
                >
                    <a-icon v-if="item.meta.icon" :type="item.meta.icon" />
                    <span> item.meta.title </span>
                </a-menu-item>
                <sub-menu v-else :key="item.path" :menu-info="item" />
            </template>
        </a-menu>
    </div>
</template>

<script>
import SubMenu from "./SubMenu.vue";
import  check  from "../utils/auth";
export default 
    props: 
        theme: 
            type: String,
            default: "dark"
        
    ,
    components: 
        "sub-menu": SubMenu
    ,
    data() 
        this.selectedKeysMap = ;
        this.openKeysMap = ;
        const menuData = this.getMenuData(this.$router.options.routes)
        return 
            collapsed: false,
            menuData,
            selectedKeys: this.selectedKeysMap[this.$route.path],
            openKeys: this.collapsed ? [] : this.openKeysMap[this.$route.path]
        ;
    ,
    watch: 
        "$route.path": function(val) 
            this.selectedKeys = this.selectedKeysMap[val];
            this.openKeys = this.collapsed ? [] : this.openKeysMap[val];
        
    ,
    methods: 
        getMenuData(routes = [], parentKeys = [], selectedKeys) 
            const menuData = [];
            for(let item of routes) 
                if(item.meta && item.meta.authority && !check(item.meta.authority)) 
                    break;
                
                if(item.name && !item.hideInMenu) 
                    this.openKeysMap[item.path] = parentKeys;
                    this.selectedKeysMap[item.path] = [selectedKeys || item.path];
                    const newItem = ...item;
                    delete newItem.children;
                    if(item.children && !item.hideChildrenInMenu) 
                        newItem.children = this.getMenuData(item.children, [...parentKeys, item.path]);
                    else
                        this.getMenuData(
                            item.children, 
                            selectedKeys ? parentKeys : [...parentKeys, item.path],
                            selectedKeys || item.path
                        );
                    
                    menuData.push(newItem);
                else if(
                    !item.hideInMenu &&
                    !item.hideChildrenInMenu &&
                    item.children
                ) 
                    menuData.push(...this.getMenuData(item.children, [...parentKeys, item.path]));
                
            
            return menuData;
        
    ,
;
</script>

以上是关于Vue 开发实战实战篇 # 32:如何使用路由管理用户权限的主要内容,如果未能解决你的问题,请参考以下文章

Vue 开发实战实战篇 # 31:如何将菜单和路由结合

Vue实战篇|使用路由管理用户权限(动态路由)

Vue 开发实战实战篇 # 41:如何管理系统中使用的图标

Vue 开发实战生态篇 # 20:选择何种模式的路由及底层原理

vue实战(7):完整开发登录页面(一)

VUE项目实战21用户列表开发-基本UI布局