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

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

说明

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



效果

访问没有权限的路由跳转到403页面3a3a5e0477a846bcb64c3f1596712943.png菜单也是根据权限进行展示,比如是user用户没有表单的权限访问

a1aaa826acfb40718f981859199a912f.png



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>



目录
相关文章
|
2天前
|
JavaScript Java 测试技术
基于springboot+vue.js+uniapp小程序的社区网格化管理平台附带文章源码部署视频讲解等
基于springboot+vue.js+uniapp小程序的社区网格化管理平台附带文章源码部署视频讲解等
15 0
基于springboot+vue.js+uniapp小程序的社区网格化管理平台附带文章源码部署视频讲解等
|
21小时前
|
JavaScript 前端开发 测试技术
使用 Vue CLI 脚手架生成 Vue 项目
通过 Vue CLI 创建 Vue 项目可以极大地提高开发效率。它不仅提供了一整套标准化的项目结构,还集成了常用的开发工具和配置,使得开发者可以专注于业务逻辑的实现,而不需要花费大量时间在项目配置上。
53 7
使用 Vue CLI 脚手架生成 Vue 项目
|
2天前
|
JavaScript 算法
“Error: error:0308010C:digital envelope routines::unsupported”启动vue项目遇到一个错误【已解决
“Error: error:0308010C:digital envelope routines::unsupported”启动vue项目遇到一个错误【已解决
8 1
|
2天前
|
JavaScript
error Component name “Login“ should always be multi-word vue/multi-word-component-names【已解决】
error Component name “Login“ should always be multi-word vue/multi-word-component-names【已解决】
6 1
|
2天前
|
JavaScript
vue知识点
vue知识点
10 3
|
2天前
|
JavaScript Java 测试技术
基于springboot+vue.js+uniapp小程序的数字化农家乐管理平台附带文章源码部署视频讲解等
基于springboot+vue.js+uniapp小程序的数字化农家乐管理平台附带文章源码部署视频讲解等
17 0
|
3天前
|
JavaScript 前端开发 Java
【vue实战项目】通用管理系统:作业列表
【vue实战项目】通用管理系统:作业列表
16 0
|
3天前
|
JavaScript API
【vue实战项目】通用管理系统:信息列表,信息的编辑和删除
【vue实战项目】通用管理系统:信息列表,信息的编辑和删除
21 2
|
10天前
|
JavaScript 前端开发 开发者
vue3+ts配置跨域报错问题解决:> newpro2@0.1.0 serve > vue-cli-service serve ERROR Invalid options in vue.
【6月更文挑战第3天】在 Vue CLI 项目中遇到 &quot;ERROR Invalid options in vue.config.js: ‘server’ is not allowed&quot; 错误是因为尝试在 `vue.config.js` 中使用不被支持的 `server` 选项。正确配置开发服务器(如代理)应使用 `devServer` 对象,例如设置代理到 `http://xxx.com/`: ```javascript module.exports = { devServer: {
24 1
|
3天前
|
JavaScript API
【vue实战项目】通用管理系统:信息列表,信息录入
【vue实战项目】通用管理系统:信息列表,信息录入
11 3