Routing role permissions for Vue and React comparison learning

Role Permissions

Role permissions, in simple terms, are which pages of the system can be seen by the logged-in user and which pages of the system cannot be seen. Generally, it is the background management system that involves such complex role permissions.

For  vue technology stacks, there are generally two ways to implement role permissions.

The first is to use  beforeEach the global pre-guard.

The second is the utilization  addRoutes method.

Let's look at the first

Real-time monitoring of user permissions through beforeEach

The core of this solution is to first  routes define the routing permissions in advance, and then  beforeEach make permission logic judgments in the global pre-guard. See if the user's role  roles matches the one we configured in the route. If it matches, it is allowed to enter, and if it does not match, it will redirect to the prompt page without permission.

define routes

First of all, we define the routing of the system. For non-homepages, we generally use routing lazy loading.

In  meta it, we can define the metadata we need, here we need to add the role of our routing roles. That is to say, the role permission that the user who enters the route needs to have. If it is not defined, it means that any role can enter.

// router/routes.js

import Home from "../views/Home.vue";

const routes = [
  {
    path: "/",
    name: "Home",
    component: Home,
    meta: {
      needLogin: false, // 不需要登录
      title: "首页",
    },
  },
  {
    path: "/about", 
    name: "About",
    component: () =>
      import(/* webpackChunkName: "about" */ "../views/About.vue"), // 路由懒加载
    meta: {
      needLogin: true, // 需要登录
      title: "关于",
      roles: ["admin", "manage"], // 该页面只有admin和普通管理员才能进入
    },
  },
  {
    path: "/nopermission", // 没权限就进入该页面
    name: "NoPermission",
    component: () =>
      import(
        /* webpackChunkName: "nopermission" */ "../views/NoPermission.vue"
      ), // 路由懒加载
    meta: {
      needLogin: true, // 需要登录
      title: "暂无权限",
    },
  },
  {
    path: "/userlist", 
    name: "UserList",
    component: () =>
      import(/* webpackChunkName: "userlist" */ "../views/UserList.vue"), // 路由懒加载
    meta: {
      needLogin: true, // 需要登录
      title: "用户管理",
      roles: ["admin"], // 该页面只有admin才能进入
    },
  },
  {
    path: "/login",
    name: "Login",
    component: () =>
      import(/* webpackChunkName: "login" */ "../views/Login.vue"), // 路由懒加载
    meta: {
      needLogin: false, // 不需要登录
      title: "登录",
    },
  },
];

export default routes;

Instantiate Router

Then create a route, which is slightly different vue2from vue3when creating a route, but it is common for route authentication.

// router/index.js

// vue2 写法
import VueRouter from "vue-router";
import routes from "./routes"

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

// vue3 写法
import { createRouter, createWebHistory } from "vue-router";
import routes from "./routes"

const router = createRouter({
  history: createWebHistory(process.env.BASE_URL),
  routes,
});

Define routing interception authentication logic

After creating the route, we can define the logic of route interception, mainly through the  beforeEach global pre-guard. Because as long as the page jumps, it will enter  beforeEach the global front guard.

The core logic here is to judge whether the page you are going to needs to log in. If you need to log in, you can further judge whether the current system has a token. If there is no token, you will be redirected to the login page.

If there is a token, further judge whether there is user information, and if there is no user information, obtain user information

After having the user information, judge whether the roles required to enter the page match the roles in the user information. If they match, they will enter the page. If they do not match, they will enter the system's unauthorized prompt page.

// router/index.js

// vue2和vue3通用
router.beforeEach(async (to, from, next) => {
  // 如果需要登录
  if (to.meta.needLogin) {
    // 获取token
    const token = localStorage.getItem("token");

    // 如果有token 则直接放行
    if (token) {
      // 获取用户信息,从store里面获取
      let userInfo = store.getters["getUserInfo"];
      // 如果没有用户信息就获取用户信息
      if (!userInfo) {
        userInfo = await store.dispatch("getUserInfoAction");
      }
      
      // 如果页面需要权限,并且用户角色不满足则去无权限提示页
      if (to.meta.roles && !to.meta.roles.includes(userInfo.role)) {
        return next("/nopermission");
      }

      next();
    } else {
      // 否则去登录页
      next("/login");
    }
  } else {
    // 不需要登录则直接放行
    next();
  }
});

// 修改标题的工作可以放在全局后置守卫
router.afterEach((to, from) => {
  if (to.meta.title) {
    document.title = to.meta.title;
  }
});

store Let's look at the logic  again 

import { createStore } from "vuex";

export default createStore({
  state: {
    userInfo: null,
  },
  getters: {
    getUserInfo: (state) => state.userInfo,
  },
  mutations: {
    setUserInfo(state, payload) {
      state.userInfo = payload;
    },
  },
  actions: {
    async getUserInfoAction({ commit }) {
      // 模拟后端获取用户信息的api
      const getUserInfoApi = () => {
        return Promise.resolve({ role: "manage", name: "jack" }); // 假设角色为 manage
      };

      const userInfo = await getUserInfoApi();

      commit("setUserInfo", userInfo);

      return userInfo;
    },
  },
});

use

After the route is created, it needs to be  main.js imported and used

import router from "./router";

// vue2写法
new Vue({
  router,
  render: (h) => h(App),
}).$mount("#app");


// vue3写法
const app = createApp(App);
app.use(router).mount("#app");

If you are not logged in, both the go aboutand userlistthe page will redirect to the login page.

After adding the simulated login to the local area token , because the user information role is  , it is no problem  manageto go  , and it will be redirected to the page without permission.about userlist 

Summarize

advantage:

The implementation is simple, and the routing permissions are configured in  meta it  roles . User information only needs to contain the role of the current user.

shortcoming:

The roles owned by the system must be known in advance, and then configured in the form of dead code  routes , and dynamic addition of roles is not supported . A system suitable for small character fixation.

Dynamically add routes through addRoutes

The core of this solution is to call the back-end interface, return the menu owned by the current user role, format it into routes, and  addRoutes dynamically add these routes to the system.

define routes

Because the route is obtained from the backend, here we only need to define the basic general route, that is, the route that does not involve permissions. Such as login page, no permission page, home page.

import Home from "../views/Home.vue";

const routes = [
  {
    path: "/",
    name: "Home",
    component: Home,
    meta: {
      title: "首页",
    },
  },
  {
    path: "/nopermission", // 没权限就进入该页面
    name: "NoPermission",
    component: () =>
      import(
        /* webpackChunkName: "nopermission" */ "../views/NoPermission.vue"
      ), // 路由懒加载
    meta: {
      title: "暂无权限",
    },
  },
  {
    path: "/login",
    name: "Login",
    component: () =>
      import(/* webpackChunkName: "login" */ "../views/Login.vue"), // 路由懒加载
    meta: {
      title: "登录",
    },
  },
];

export default routes;

Instantiate Router

Then create a route, vue2which vue3is slightly different from when creating a route.

// router/index.js

// vue2 写法
import VueRouter from "vue-router";
import routes from "./routes"

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

// vue3 写法
import { createRouter, createWebHistory } from "vue-router";
import routes from "./routes"

const router = createRouter({
  history: createWebHistory(process.env.BASE_URL),
  routes,
});

Define routing interception authentication logic

After creating the route, we can define the logic of dynamically adding routes.

The core logic here is to judge whether the page you are going to is in the whitelist. If it is not in the whitelist, it will further judge whether the current system has a token. If there is no token, it will redirect to the login page.

If there is a token, further judge whether there is user menu information, and if there is no user menu information, obtain user menu information

After having the user menu information, first convert the menu information into the format required by the front-end routing, and then dynamically add the route to the system through the addRoutes method.

When the user goes to a route that does not exist, the name attribute of the route will be  undefined, so it is redirected to an unauthorized prompt page

// router/index.js

// vite创建的项目 使用这种方法实现动态加载
const modules = import.meta.glob("../views/*.vue");

// 转换成 vue-router 需要的格式
const transformRoute = (menus) => {
  return menus.map((menu) => {
    return {
      path: menu.path,
      name: menu.name,
      component: modules[menu.component],
      meta: {
        title: menu.title,
      },
    };
  });
};

// vue3需要手动实现该方法
const addRoutes = (routes) => {
  routes.forEach((route) => {
    router.addRoute(route);
  });
};

// 白名单页面,不需要权限
const whiteLists = ["/login", "/"];

router.beforeEach(async (to, from, next) => {
  // 是否是白名单
  if (!whiteLists.includes(to.path)) {
    // 获取token
    const token = localStorage.getItem("token");

    // 如果有token
    if (token) {
      // 获取用户菜单信息,从store里面获取
      let userMenus = store.getters["getUserMenus"];
      // 如果没有用户菜单信息就获取用户菜单信息
      if (!userMenus) {
        userMenus = await store.dispatch("getUserMenuAction");
        // 菜单转成路由
        const userRoute = transformRoute(userMenus);
        
        // 动态添加路由 vue2 和 vue3 有细微差别
        // vue2
        // router.addRoutes(userRoute)

        // vue3
        // 因为 vue3 移除了 router.addRoutes()方法,所以需要手动实现addRoutes方法。
        addRoutes(userRoute);

        return next({ ...to });
      }

      // 有name说明路由存在,否则说明没有该路由
      if (to.name) {
        next();
      } else {
        // 去无权限页面
        next("/nopermission");
      }
    } else {
      // 否则去登录页
      next("/login");
    }
  } else {
    // 是白名单则直接进入
    next();
  }
});

// 修改标题的工作可以放在全局后置守卫
router.afterEach((to, from) => {
  if (to.meta.title) {
    document.title = to.meta.title;
  }
});

store Let's look at the logic  again 

import { createStore } from "vuex";

export default createStore({
  state: {
    userMenus: null,
  },
  getters: {
    getUserMenus: (state) => state.userMenus,
  },
  mutations: {
    setUserMenus(state, payload) {
      state.userMenus = payload;
    },
  },
  actions: {
    async getUserMenuAction({ commit }) {
      // 模拟后端获取用户菜单信息api
      const getUserMenuApi = () => {
        // 假设只有about菜单
        return Promise.resolve([
          {
            path: "/about",
            name: "About",
            component: "../views/About.vue",
            title: "关于",
          },
        ]);
      };

      const userMenus = await getUserMenuApi();

      commit("setUserMenus", userMenus);

      return userMenus;
    },
  },
});

use

After the route is created, it needs to be imported and used main.js 

import router from "./router";

// vue2写法
new Vue({
  router,
  render: (h) => h(App),
}).$mount("#app");


// vue3写法
const app = createApp(App);
app.use(router).mount("#app");

In the case of not logged in, the Go aboutand userlistpage will redirect to the login page.

Add it locally token. After the simulated login is completed, because the user abouthas  a menu, about it is no problem to go to the page. Going to  userlist the page will redirect you to a page without permission.

Summarize

advantage:

System roles may not be fixed, and dynamic addition of roles is supported . It is suitable for background large-scale management system.

shortcoming:

The implementation is relatively complicated and requires more back-end cooperation.

Summarize

The advantage of the first  beforeEach method of monitoring user permissions in real time is that it is simple to implement, and the routing permissions are  configured meta in  roles it. User information only needs to contain the role of the current user. The disadvantage is also obvious. The roles owned by the system must be known in advance, and then configured in the form of dead code  routes , and dynamic addition of roles is not supported . The author thinks that it is very good if it is a system with fixed roles, such as a library management system, a teacher management system, etc.

addRoutes The second way to achieve role permissions by  dynamically adding routes has the advantage that the system roles can not be fixed, and dynamic addition of roles is supported . It is very suitable for large-scale management systems in the background, and can create role assignment menus in real time.

For example, the low-code background management system I made has a series of functions such as creating menus, roles, and users in real time.

 

おすすめ

転載: blog.csdn.net/huihui_999/article/details/131828573