您的位置:

Vue路由权限详解

一、路由权限管理的背景和目的

路由权限管理是前端开发中常见的需求,主要目的是控制用户或角色对某些页面的访问权限。在一个Web应用中,有些页面只能是管理员或VIP用户才能访问,比如后台管理系统或支付页面。如果没有路由权限管理,普通用户可能会通过直接输入URL来访问到这些页面。为了保护应用的安全性和用户的隐私,需要对这些页面进行权限控制,仅允许有权限的用户访问。

二、基本实现方式

在Vue中,可以通过Vue Router来管理路由。权限管理的实现方式主要有以下几种:

  1. 在路由的meta字段中添加需要的权限信息,然后在路由导航守卫中进行鉴权控制
  2. 在路由组件的created或mounted生命周期中进行鉴权控制
  3. 通过Vuex来管理用户的登陆状态以及权限,然后在路由导航守卫中进行鉴权控制

1. 在路由的meta字段中添加需要的权限信息

  
// 定义路由
const routes = [
  {
    path: '/admin',
    name: 'admin',
    component: Admin,
    meta: {
      requiresAuth: true, // 需要登录才能访问
      isAdmin: true // 需要是管理员才能访问
    }
  },
  // 其他路由...
];

// 导航守卫
router.beforeEach((to, from, next) => {
  if (to.matched.some(record => record.meta.requiresAuth) && !isAuthenticated()) {
    // 还未登录,跳转到登录页面
    next('/login');
  } else if (to.matched.some(record => record.meta.isAdmin) && !isAdmin()) {
    // 不是管理员,没有权限
    next('/404');
  } else {
    next();
  }
});
  

2. 在路由组件的created或mounted生命周期中进行鉴权控制

  
// 定义路由
const routes = [
  {
    path: '/admin',
    name: 'admin',
    component: Admin,
    meta: {
      requiresAuth: true, // 需要登录才能访问
    }
  },
  // 其他路由...
];

// 在路由组件中进行鉴权控制
export default {
  name: 'Admin',
  created() {
    if (!isAuthenticated()) {
      // 还未登录,跳转到登录页面
      this.$router.push('/login');
    }
  }
};
  

3. 通过Vuex来管理用户的登陆状态以及权限

  
// 在Vuex中定义state、actions和mutations
const state = {
  isAuthenticated: false,
  isAdmin: false
};

const actions = {
  login({ commit }) {
    // 登录成功后,设置isAuthenticated为true
    commit('setIsAuthenticated', true);
  },
  logout({ commit }) {
    // 登出后,重置isAuthenticated为false
    commit('setIsAuthenticated', false);
  },
  setIsAdmin({ commit }, isAdmin) {
    // 根据用户的角色设置isAdmin
    commit('setIsAdmin', isAdmin);
  }
};

const mutations = {
  setIsAuthenticated(state, isAuthenticated) {
    state.isAuthenticated = isAuthenticated;
  },
  setIsAdmin(state, isAdmin) {
    state.isAdmin = isAdmin;
  }
};

// 定义路由
const routes = [
  {
    path: '/admin',
    name: 'admin',
    component: Admin,
    meta: {
      requiresAuth: true, // 需要登录才能访问
      isAdmin: true // 需要是管理员才能访问
    }
  },
  // 其他路由...
];

// 导航守卫
router.beforeEach((to, from, next) => {
  if (to.matched.some(record => record.meta.requiresAuth) && !state.isAuthenticated) {
    // 还未登录,跳转到登录页面
    next('/login');
  } else if (to.matched.some(record => record.meta.isAdmin) && !state.isAdmin) {
    // 不是管理员,没有权限
    next('/404');
  } else {
    next();
  }
});
  

三、路由权限管理的进一步优化

基本实现方式可以满足一般的需求,但有时还需要更精细的权限控制。比如,一个页面可能不仅要求用户已登录,还需要用户拥有某种特定的角色才能访问。这时需要对路由权限控制进行进一步的优化。

1. 根据用户角色动态生成路由

某些页面只有管理员才能访问,而管理员账号可以随时添加或删除。在这种情况下,如果将需要管理员才能访问的路由信息写死在代码中,那么每次管理员账号变化时都需要修改代码。为了解决这个问题,可以根据用户角色动态生成路由。

  
// 在路由组件之外定义路由配置
export const asyncRoutes = [
  {
    path: '/admin',
    name: 'admin',
    component: Admin,
    meta: {
      requiresAuth: true,
      isAdmin: true
    }
  },
  {
    path: '/vip',
    name: 'vip',
    component: Vip,
    meta: {
      requiresAuth: true,
      isVip: true
    }
  },
  // 其他路由...
];

// 在router.js中引入路由配置
import { asyncRoutes } from './routes';

// 定义静态路由
const routes = [
  {
    path: '/',
    name: 'Home',
    component: Home
  },
  {
    path: '/login',
    name: 'Login',
    component: Login
  },
  // 其他路由...
];

// 根据用户角色生成路由
router.beforeEach((to, from, next) => {
  // 获取当前用户角色
  const role = store.state.role;

  // 动态生成路由
  const accessRoutes = asyncRoutes.filter(route => {
    if (route.meta[role]) {
      return true;
    }
    return false;
  });

  // 将动态生成的路由添加到路由器中
  router.addRoutes(accessRoutes);

  next();
});
  

2. 控制菜单的显示和隐藏

在应用中,菜单是常见的元素之一。有时需要在菜单中只显示当前用户有权限访问的页面,而隐藏不能访问的页面。为了实现这一功能,需要在菜单组件中根据用户权限动态生成菜单。

  
// 在菜单组件中根据用户角色动态生成菜单

   

<script>
  import { asyncRoutes } from '../router/routes';
  export default {
    data() {
      return {
        menu: []
      };
    },
    mounted() {
      // 获取当前用户角色
      const role = store.state.role;

      // 动态生成菜单
      const menu = asyncRoutes.filter(route => {
        if (route.meta[role]) {
          return true;
        }
        return false;
      }).map(route => {
        const item = {
          path: route.path,
          title: route.meta.title,
        };

        if (route.children && route.children.length > 0) {
          item.children = route.children.map(child => {
            return {
              path: child.path,
              title: child.meta.title
            };
          });
        }

        return item;
      });

      this.menu = menu;
    }
  };
</script>
  

3. 根据路由层级进行权限控制

有些页面只有在特定的父级页面下才能访问。例如,在后台管理系统中,账号管理和订单管理页面只有在管理员设置页面下才能访问。为了解决这个问题,可以在路由配置中使用嵌套路由,并在导航守卫中根据路由层级进行权限控制。

  
// 在路由组件中定义嵌套路由
const routes = [
  {
    path: '/admin',
    name: 'admin',
    component: Admin,
    meta: {
      requiresAuth: true, // 需要登录才能访问
      isAdmin: true // 需要是管理员才能访问
    },
    children: [
      {
        path: 'account',
        name: 'account',
        component: Account,
        meta: {
          requiresParent: 'admin' // 只有在admin下才能访问
        }
      },
      {
        path: 'order',
        name: 'order',
        component: Order,
        meta: {
          requiresParent: 'admin' // 只有在admin下才能访问
        }
      }
    ]
  },
  // 其他路由...
];

// 导航守卫中根据路由层级进行权限控制
router.beforeEach((to, from, next) => {
  if (to.matched.some(record => record.meta.requiresAuth) && !isAuthenticated()) {
    // 还未登录,跳转到登录页面
    next('/login');
  } else if (to.matched.some(record => record.meta.requiresParent)) {
    // 需要在特定的父级页面下
    const parentRoute = to.matched[1];
    if (parentRoute.name !== to.meta.requiresParent) {
      next('/404');
    } else {
      next();
    }
  } else {
    next();
  }
});