【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>



目录
相关文章
|
4天前
|
JavaScript
vue使用iconfont图标
vue使用iconfont图标
35 1
|
14天前
|
JavaScript 关系型数据库 MySQL
基于VUE的校园二手交易平台系统设计与实现毕业设计论文模板
基于Vue的校园二手交易平台是一款专为校园用户设计的在线交易系统,提供简洁高效、安全可靠的二手商品买卖环境。平台利用Vue框架的响应式数据绑定和组件化特性,实现用户友好的界面,方便商品浏览、发布与管理。该系统采用Node.js、MySQL及B/S架构,确保稳定性和多功能模块设计,涵盖管理员和用户功能模块,促进物品循环使用,降低开销,提升环保意识,助力绿色校园文化建设。
|
2月前
|
JavaScript API 开发者
Vue是如何进行组件化的
Vue是如何进行组件化的
|
2月前
|
JavaScript 前端开发 开发者
Vue是如何劫持响应式对象的
Vue是如何劫持响应式对象的
32 1
|
2月前
|
JavaScript 前端开发 API
介绍一下Vue中的响应式原理
介绍一下Vue中的响应式原理
33 1
|
2月前
|
JavaScript 前端开发 开发者
Vue是如何进行组件化的
Vue是如何进行组件化的
|
2月前
|
存储 JavaScript 前端开发
介绍一下Vue的核心功能
介绍一下Vue的核心功能
|
2月前
|
JavaScript 前端开发 开发者
vue学习第一章
欢迎来到我的博客!我是瑞雨溪,一名热爱前端的大一学生,专注于JavaScript与Vue,正向全栈进发。博客分享Vue学习心得、命令式与声明式编程对比、列表展示及计数器案例等。关注我,持续更新中!🎉🎉🎉
45 1
vue学习第一章
|
2月前
|
JavaScript 前端开发 索引
vue学习第三章
欢迎来到瑞雨溪的博客,一名热爱JavaScript与Vue的大一学生。本文介绍了Vue中的v-bind指令,包括基本使用、动态绑定class及style等,希望能为你的前端学习之路提供帮助。持续关注,更多精彩内容即将呈现!🎉🎉🎉
32 1
|
2月前
|
缓存 JavaScript 前端开发
vue学习第四章
欢迎来到我的博客!我是瑞雨溪,一名热爱JavaScript与Vue的大一学生。本文介绍了Vue中计算属性的基本与复杂使用、setter/getter、与methods的对比及与侦听器的总结。如果你觉得有用,请关注我,将持续更新更多优质内容!🎉🎉🎉
39 1
vue学习第四章

热门文章

最新文章