美文网首页前端Vuejs css html
从0实现后台管理系统的权限处理

从0实现后台管理系统的权限处理

作者: 扶得一人醉如苏沐晨 | 来源:发表于2023-04-09 15:13 被阅读0次

一、路由配置(router-----index.js)

import Vue from "vue";
import VueRouter from "vue-router";
import Layout from "@/views/Layout";
import Login from "@/views/Login";
import Home from "@/views/Home";
// 物品管理
import GoodsMgr from "@/views/GoodsMgr";
import List from "@/views/GoodsMgr/List";
import Catagory from "@/views/GoodsMgr/Catagory";
// 订单管理
import OrderMgr from "@/views/OrderMgr";
import OrderList from "@/views/OrderMgr/OrderList";
import Collect from "@/views/OrderMgr/Collect";
// 系统管理
import System from "@/views/System";
import Dept from "@/views/System/Dept";
import Role from "@/views/System/Role";
import User from "@/views/System/User";

Vue.use(VueRouter);

const routes = [
  {
    path: "/",
    component: Layout,
    children: [
      { path: "/", name: "home", component: Home },
      {
        path: "/goods",
        name: "goods",
        component: GoodsMgr,
        children: [
          { path: "list", name: "list", component: List },
          {
            path: "catagory",
            name: "catagory",
            component: Catagory,
          },
        ],
      },
      {
        path: "/order",
        name: "order",
        component: OrderMgr,
        children: [
          { path: "list", name: "list", component: OrderList },
          {
            path: "collect",
            name: "collect",
            component: Collect,
          },
        ],
      },
      {
        path: "/system",
        name: "system",
        component: System,
        children: [
          { path: "dept", name: "dept", component: Dept },
          {
            path: "role",
            name: "role",
            component: Role,
          },
          {
            path: "user",
            name: "user",
            component: User,
          },
        ],
      },
    ],
  },
  {
    path: "/login",
    name: "login",
    component: Login,
  },
];

const router = new VueRouter({
  routes,
});

export default router;

二、权限控制

2.1、在路由配置中文layout路由添加元信息

(layout下面的所有子路由都需要认证)

{
    path: "/",
    meta: {
      isAuth: true,
    },
    component: Layout,
    children: [{ path: "/", name: "home", component: Home }],
  },

2.2、在router文件夹下面新建permission.js文件

import router from "./index";
import store from "@/store";

// 全局导航守卫
router.beforeEach((to, from, next) => {
  // 在匹配到的路由数组中,如果没有找到需要权限的直接放行
  if (to.matched.length && !to.matched.some((item) => item.meta.isAuth)) {
    next();
  } else {
    //判断是否已经登录
    let token = store.state.userinfo.token;
    if (token) {
      next();
    } else {
      next("/login");
    }
  }
});

2.3、引入permission.js

// 引入权限控制
import "@/router/permission";

三、登录实现

3.1、Vuex登录模块封装

在store文件夹下面新建modules文件,modules下面新建login.js

export default {
  namespaced: true,
  state: {
    userinfo: {
      user: "",
      token: "",
    },
  },
  mutations: {
    setUser(state, payload) {
      state.userinfo = payload;
    },
    deleteUser(state) {
      state.userinfo = {
        user: "",
        token: "",
      };
    },
  },
};

引入模块index.js中

import Vue from "vue";
import Vuex from "vuex";
import login from "./modules/login";

Vue.use(Vuex);

export default new Vuex.Store({
  state: {},
  getters: {},
  mutations: {},
  actions: {},
  modules: {
    login,
  },
});

3.2、登录成功操作

  • 用户输入账号密码,登录成功
  • 调用Vuex的登录模块setUser,存储用户信息,路由跳转到layout


    image.png

四、将路由拆分

4.1、提取动态路由

在router文件夹下面新建menuList.js,用于存放动态路由


image.png

menuList.js代码

// 物品管理
import GoodsMgr from "@/views/GoodsMgr";
import List from "@/views/GoodsMgr/List";
import Catagory from "@/views/GoodsMgr/Catagory";
// 订单管理
import OrderMgr from "@/views/OrderMgr";
import OrderList from "@/views/OrderMgr/OrderList";
import Collect from "@/views/OrderMgr/Collect";
// 系统管理
import System from "@/views/System";
import Dept from "@/views/System/Dept";
import Role from "@/views/System/Role";
import User from "@/views/System/User";
export const menuList = [
  {
    path: "/goods",
    name: "goods",
    component: GoodsMgr,
    children: [
      { path: "list", name: "list", component: List },
      {
        path: "catagory",
        name: "catagory",
        component: Catagory,
      },
    ],
  },
  {
    path: "/order",
    name: "order",
    component: OrderMgr,
    children: [
      { path: "list", name: "list", component: OrderList },
      {
        path: "collect",
        name: "collect",
        component: Collect,
      },
    ],
  },
  {
    path: "/system",
    name: "system",
    component: System,
    children: [
      { path: "dept", name: "dept", component: Dept },
      {
        path: "role",
        name: "role",
        component: Role,
      },
      {
        path: "user",
        name: "user",
        component: User,
      },
    ],
  },
];

4.2、登录页和首页home存放于index.js

import Vue from "vue";
import VueRouter from "vue-router";
import Layout from "@/views/Layout";
import Login from "@/views/Login";
import Home from "@/views/Home";

Vue.use(VueRouter);
// 基础路由(所有用户均可访问)
export const baseRoutes = [
  {
    path: "/",
    component: Layout,
    children: [{ path: "/", name: "home", component: Home }],
  },
];
// 登录页路由
export const routes = [
  {
    path: "/login",
    name: "login",
    component: Login,
  },
];

const router = new VueRouter({
  routes,
});

export default router;

五、方法封装(深拷贝和路由菜单比对)

新建util文件夹---新建index.js

/**
 * 对象深拷贝
 */
export const deepClone = (data) => {
  var type = getObjType(data);
  var obj;
  if (type === "array") {
    obj = [];
  } else if (type === "object") {
    obj = {};
  } else {
    // 不再具有下一层次
    return data;
  }
  if (type === "array") {
    for (var i = 0, len = data.length; i < len; i++) {
      obj.push(deepClone(data[i]));
    }
  } else if (type === "object") {
    for (var key in data) {
      obj[key] = deepClone(data[key]);
    }
  }
  return obj;
};
//前端总路由和后端返回的权限路由作比对筛选出具有权限的路由
export function rulesMenu(menuList, dyMenuList) {
  // 最终筛选出来的路由
  let menu = [];
  const arr = deepClone(menuList);
  arr.forEach((one) => {
    dyMenuList.forEach((two) => {
      if (one.path === two.path) {
        if (two.children && two.children.length > 0) {
          one.children = rulesMenu(one.children, two.children);
        }
        // 添加
        menu.push(one);
      }
    });
  });
  return menu;
}

六、动态路由处理

5.1、封装Vuex的menu.js模块

modules文件夹下面新建menu.js

image.png

menu.js

// 接口获取后端返回的动态菜单
import { permission } from "@/api/index";
// menuList 需要权限控制路由(完整)
import { menuList } from "@/router/menuList";
// baseRoutes 包含layout和home路由
import { baseRoutes } from "@/router/index";
// 深拷贝方法和菜单路由比对
import { deepClone, rulesMenu } from "@/util/index";
  
export default {
  namespaced: true,
  state: {
    dyMenuList: [], //动态路由导航
  },
  mutations: {
    setMenuList(state, payload) {
      state.dyMenuList = payload;
    },
    deleteMenuList(state) {
      state.dyMenuList = [];
    },
  },
  actions: {
    getMenuList({ commit, state, rootState }) {
      return new Promise((resolve, reject) => {
        permission({ token: rootState.login.userinfo.token })
          .then((res) => {
            console.log("后端返回的动态路由------------", res.data.data);
            console.log("前端定义的完整路由------------", menuList);
            // 比较前后端的路由文件----筛选出符合条件的路由文件
            let menus = rulesMenu(menuList, res.data.data);
            console.log("筛选出来的路由------------", menus);
            console.log("获取的基本路由layout-------", baseRoutes);
            // 深拷贝一份
            let arr = deepClone(baseRoutes);
            // 合并路由导航
            let routes = arr[0].children; //获取layout布局里面的子路由数组
            // 将筛选后的菜单放置到子路由数组
            routes.push(...menus);
            console.log("动态组装后的路由-------", arr);
            console.log("合并后的子路由数组-------", routes);

            commit("setMenuList", routes);
            // 动态添加路由
            /* 
            router.addRoutes 已废弃: 使用 router.addRoute() 代替
             */
            resolve(arr);
          })
          .catch((err) => {});
      });
    },
  },
};

引入menu.js模块

import Vue from "vue";
import Vuex from "vuex";
import login from "./modules/login";
import menu from "./modules/menu";

Vue.use(Vuex);

export default new Vuex.Store({
  state: {},
  getters: {},
  mutations: {},
  actions: {},
  modules: {
    login,
    menu,
  },
});

七、修改全局路由守卫permission.js

import router from "./index";
import store from "@/store";

// 全局导航守卫
router.beforeEach((to, from, next) => {
  // 在匹配到的路由数组中,如果没有找到需要权限的直接放行
  if (to.matched.length && !to.matched.some((item) => item.isAuth)) {
    next();
  } else {
    //判断是否已经登录
    let token = store.state.userInfo.token;
    if (token) {
      // 判断是否有导航存储到Vuex中,如果有就进入,没有动态获取
      if (store.state.menu.dyMenuList.length !== 0) {
        next();
      } else {
        store.dispatch("menu/getMenuList").then((baseRoutes) => {
          // 动态添加路由
          /* 
            router.addRoutes 已废弃: 使用 router.addRoute() 代替
             */
          // router.addRoutes(baseRoutes); //废弃
          baseRoutes.forEach((element) => {
            router.addRoute(element);
          });
          // next({ ...to, replace: true }) //中断当前导航。执行新的导航
          next({ ...to, replace: true });
        });
      }
    } else {
      next("/login");
    }
  }
});

相关文章

  • 权限设计(下) - 细说权限设计

    什么是权限管理一般来说,只要有用户参与的系统,那么都要有权限管理,尤其是一些后台的管理系统,权限管理可以实现对用户...

  • 手把手教你搞定权限管理,结合Spring Security实现接

    权限控管理作为后台管理系统中必要的功能,mall项目中结合Spring Security实现了基于路径的动态权限控...

  • vue后台管理系统中的权限控制

    0.背景和目的 后台管理系统一般都少不了登录权限控制,这里我们讨论以下如何实现权限控制。 1.主要概念 一个完整的...

  • 演习开发

    后台管理系统 、后台管理系统的接口lmy-admin-apispringboot开发restful的接口,权限管理...

  • 20 演习开发

    后台管理系统 、后台管理系统的接口lmy-admin-apispringboot开发restful的接口,权限管理...

  • 演习开发--蓝墨云班课

    后台管理系统 后台管理系统的接口Imy-admin-api SpringBoot开发RESTful的接口,权限管理...

  • 如何快速搭建一个管理后台-权限管理

    0. 系统设计1. 数据管理2. 身份认证3. 权限管理 身份认证处理的是 “你是谁的问题”,而权限管理处理的是 ...

  • 摘录 - 如何做权限管理系统设计

    权限管理系统定义 权限管理是一个几乎所有后台系统的都会涉及的一个重要组成部分,主要目的是对整个后台管理系统进行权限...

  • NodeJS搭建业务系统

    一、项目需求:实现公司内部B端业务系统,包含用户管理系统,公司管理系统,成员管理系统,权限管理系统,为公司业务处理...

  • Mobx实例应用

    背景: 这个问题要从一个后台管理系统的权限管理开始说起,我们将后台权限管理系统可以分为几个层级,如下: 账号登录,...

网友评论

    本文标题:从0实现后台管理系统的权限处理

    本文链接:https://www.haomeiwen.com/subject/rmhbddtx.html