[VUE]路由权限管理

文章讲述了如何在VueRouter中使用`meta`的`roles`属性为不同的路由分配权限,通过`hasPermission`和`filterAsyncRoutes`函数实现用户角色对路由的访问控制,同时结合Vuex存储管理路由权限状态。
摘要由CSDN通过智能技术生成

addRoute实现路由权限

router.js

在router.js中在meta里使用role赋予路由权限,比如在下面的代码中我有四种用户user,A,B,C,我希望他们能访问的路由不同。其中登录页面是统一的,把他放在constantRoutes 中,404页面也是统一的,但是由于404页面必须最后加载,不然所有的页面都会被拦截到404,因此我们把他放在了asyncRoutes的最后一个。

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

Vue.use(Router);

import Layout from "@/layout";

export const asyncRoutes = [
  {
    path: "/dashboard",
    component: Layout,
    redirect: "/dashboard",
    meta: {
      title: "首页",
      requiresAuth: true,
      roles: ["user"],
    },
    children: [
      {
        path: "dashboard",
        name: "Dashboard",
        component: () => import("@/views/user/dashboard/index"),
        meta: {
          title: "首页",
          requiresAuth: true,
        },
      },
    ],
  },
  {
    path: "/downloadList",
    component: Layout,
    meta: {
      title: "下载记录",
      requiresAuth: true,
      roles: ["user"],
    },
    children: [
      {
        path: "downloadList",
        name: "DownloadList",
        component: () => import("@/views/user/downloadRecord/index"),
        meta: {
          title: "下载记录",
          requiresAuth: true,
          roles: ["user"],
        },
      },
    ],
  },
  {
    path: "/user_manage",
    component: Layout,
    meta: {
      title: "用户管理",
      roles: ["A", "B", "C"],
      icon: "userManage",
    },
    children: [
      {
        path: "user",
        name: "User",
        component: () => import("@/views/admin/userManage/index"),
        meta: {
          title: "用户管理",
          roles: ["A", "B", "C"],
          icon: "userManage",
        },
        requiresAuth: true,
      },
    ],
  },
 
  {
    path: "/task_manage",
    component: Layout,
    meta: { title: "任务管理", roles: ["A", "B"], icon: "taskManage" },
    children: [
      {
        path: "task",
        name: "Task",
        component: () => import("@/views/admin/taskManage/index"),
        meta: { title: "任务管理", roles: ["A", "B"], icon: "taskManage" },
        requiresAuth: true,
      },
    ],
  },
  {
    path: "/ssn_manage",
    component: Layout,
    meta: { title: "SSN管理", roles: ["A", "B"], icon: "announceManage" },
    children: [
      {
        path: "ssn",
        name: "SSN",
        component: () => import("@/views/admin/ssnManage/index"),
        meta: { title: "SSN管理", roles: ["A", "B"], icon: "announceManage" },
        requiresAuth: true,
      },
    ],
  },
  { path: "*", redirect: "/404", hidden: true },
];

export const constantRoutes = [
  {
    path: "/login",
    component: () => import("@/views/user/login/index"),
    hidden: true,
  },
];

const createRouter = () =>
  new Router({
    // mode: 'history', // require service support
    scrollBehavior: () => ({ y: 0 }),
    routes: constantRoutes,
  });

const router = createRouter();

// Detail see: https://github.com/vuejs/vue-router/issues/1234#issuecomment-357941465
export function resetRouter() {
  const newRouter = createRouter();
  router.matcher = newRouter.matcher; // reset router
}

export default router;

store/permission.js

这段代码主要是为了对路由进行验证

  1. 权限检查函数 (hasPermission): 该函数用于检查用户是否有权限访问特定路由,通过检查路由元数据中指定的角色信息。
  2. 异步路由过滤函数 (filterAsyncRoutes): 该函数基于用户的角色递归地过滤异步路由,以确保用户只能访问其具有权限的路由。
  3. 模块动作 (actions): 包含生成路由和清除路由两个动作。生成路由的动作会调用异步路由过滤函数,并将结果提交到状态中;清除路由的动作用于清空路由信息。
import { asyncRoutes, constantRoutes } from "@/router";

/**
 * 用 meta.role判断当前路由是否有权限
 * @param roles
 * @param route
 */
function hasPermission(roles, route) {
  if (route.meta && route.meta.roles) {
    return route.meta.roles.some((item: any) => roles.includes(item));
  } else {
    return false;
  }
}

/**
 * 过滤路由
 * @param routes asyncRoutes
 * @param roles
 */
export function filterAsyncRoutes(routes, roles) {
  const res = [];
  routes.forEach((route) => {
    const tmp = { ...route };
    if (hasPermission(roles, tmp)) {
      if (tmp.children) {
        tmp.children = filterAsyncRoutes(tmp.children, roles);
      }
      res.push(route);
    } else {
      hasPermission(roles, tmp);
    }
  });
  return res;
}

const state = {
  routes: [],
  addRoutes: [],
};

const mutations = {
  SET_ROUTES: (state, routes) => {
    state.addRoutes = routes;
    state.routes = constantRoutes.concat(routes);
  },
};

const actions = {
  generateRoutes({ commit }, roles) {
    return new Promise((resolve) => {
      let accessedRoutes;
      accessedRoutes = filterAsyncRoutes(asyncRoutes, roles);
      commit("SET_ROUTES", accessedRoutes);
      resolve(accessedRoutes);
    });
  },
  clearRoutes({ commit }) {
    commit("SET_ROUTES", []);
  },
};

export default {
  namespaced: true,
  state,
  mutations,
  actions,
};

permission.js

在这个文件里调用action过滤路由,获得符合当前角色的路由,可以直接写在main.js里,这里我们把他单独放在permission.js中,再从main.js引入。在这个文件里调用action过滤路由,获得符合当前角色的路由,可以直接写在main.js里,这里我们把他单独放在permission.js中,再从main.js引入。这里需要注意前面判断用户是否登录的逻辑可以自己定义但是在调用权限判定的action前一定要判断permission_routes是否已经有值,否则会进入无限循环。也就是
if (hasRoutes) {
next();
} 这一步。

import router from "./router";
import store from "./store";
import { Message } from "element-ui";
import NProgress from "nprogress"; // progress bar
import "nprogress/nprogress.css"; // progress bar style
import { getUsername, getRole } from "@/utils/auth"; // get token from cookie
import getPageTitle from "@/utils/get-page-title";

NProgress.configure({ showSpinner: false }); // NProgress Configuration

const whiteList = ["/login"]; // no redirect whitelist

router.beforeEach(async (to, from, next) => {
  // start progress bar
  NProgress.start();

  document.title = getPageTitle(to.meta.title);
  // set page title

  const hasName = getUsername();
  const hasRole = getRole();

  if (hasName && hasRole) {
    if (to.path === "/login") {
      next();
      NProgress.done();
    } else {
      const hasRoutes =
        store.getters.permission_routes &&
        store.getters.permission_routes.length > 0;//如果已经有permission_routes就不再遍历
      if (hasRoutes) {
        next();
      } else {
        try {
          // generate accessible routes map based on roles
          const accessRoutes = await store.dispatch(
            "permission/generateRoutes",
            [store.getters.roles]
          );
          router.addRoutes(accessRoutes);
          next({ ...to, replace: true });
        } catch (error) {
          // remove token and go to login page to re-login
          // await store.dispatch("user/resetToken");
          Message.error(error || "Has Error");
          next(`/login`);
          NProgress.done();
        }
      }
    }
  } else {
    /* has no token*/
    if (whiteList.indexOf(to.path) !== -1) {
      // in the free login whitelist, go directly
      next();
    } else {
      // other pages that do not have permission to access are redirected to the login page.
      next(`/login?redirect=${to.path}`);
      NProgress.done();
    }
  }
});

router.afterEach(() => {
  // finish progress bar
  NProgress.done();
});

侧边栏

遍历之前过滤出来的permission_routers,通过vuex拿到之后动态v-for渲染。

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我有一个小脑瓜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值