Vue2简单实现一个权限管理

以下是基于 Vue2 实现的基础权限管理方案 ,涵盖路由权限控制、按钮权限控制、指令封装等核心功能,适合中小型后台系统:

一、权限数据设计

首先定义用户权限结构(通常从后端接口获取):

javascript 复制代码
// src/store/modules/auth.js
const state = {
  // 用户角色(如 ['admin', 'editor'])
  roles: [],
  // 用户拥有的权限码(如 ['user:add', 'user:edit'])
  permissions: []
};

const mutations = {
  SET_ROLES(state, roles) {
    state.roles = roles;
  },
  SET_PERMISSIONS(state, permissions) {
    state.permissions = permissions;
  }
};

const actions = {
  // 模拟从后端获取权限(实际项目中替换为接口请求)
  getAuth({ commit }) {
    return new Promise(resolve => {
      // 假设后端返回的权限数据
      const authData = {
        roles: ['editor'],
        permissions: ['dashboard:view', 'user:view', 'user:edit']
      };
      commit('SET_ROLES', authData.roles);
      commit('SET_PERMISSIONS', authData.permissions);
      resolve();
    });
  }
};

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

二、路由权限控制

通过路由守卫 过滤无权限的路由,结合VueRouter的动态路由添加:

1. 定义路由规则(区分公开 / 私有路由)

javascript 复制代码
// src/router/index.js
import Vue from 'vue';
import Router from 'vue-router';
import store from '@/store';

Vue.use(Router);

// 公开路由(无需权限)
export const constantRoutes = [
  {
    path: '/login',
    component: () => import('@/views/login')
  },
  {
    path: '/404',
    component: () => import('@/views/404')
  }
];

// 私有路由(需权限)
export const asyncRoutes = [
  {
    path: '/',
    component: () => import('@/layout'),
    redirect: '/dashboard',
    children: [
      {
        path: 'dashboard',
        component: () => import('@/views/dashboard'),
        meta: { 
          title: '首页', 
          roles: ['admin', 'editor'], // 需要的角色
          permissions: ['dashboard:view'] // 需要的权限码
        }
      }
    ]
  },
  {
    path: '/user',
    component: () => import('@/layout'),
    children: [
      {
        path: 'list',
        component: () => import('@/views/user/list'),
        meta: { 
          title: '用户列表', 
          permissions: ['user:view'] 
        }
      },
      {
        path: 'edit/:id',
        component: () => import('@/views/user/edit'),
        meta: { 
          title: '编辑用户', 
          permissions: ['user:edit'] 
        }
      }
    ]
  },
  { path: '*', redirect: '/404', hidden: true }
];

const createRouter = () => new Router({
  routes: constantRoutes
});

const router = createRouter();

export default router;

2. 路由守卫实现权限过滤

javascript 复制代码
// src/permission.js
import router from './router';
import store from './store';
import { asyncRoutes, constantRoutes } from './router';

// 权限判断函数:检查是否有角色/权限
function hasPermission(roles, permissions, route) {
  if (route.meta && route.meta.roles) {
    // 角色校验
    return roles.some(role => route.meta.roles.includes(role));
  }
  if (route.meta && route.meta.permissions) {
    // 权限码校验
    return permissions.some(perm => route.meta.permissions.includes(perm));
  }
  return true; // 无权限配置则默认可见
}

// 过滤私有路由
function filterAsyncRoutes(routes, roles, permissions) {
  const res = [];
  routes.forEach(route => {
    const tmp = { ...route };
    if (hasPermission(roles, permissions, tmp)) {
      if (tmp.children) {
        tmp.children = filterAsyncRoutes(tmp.children, roles, permissions);
      }
      res.push(tmp);
    }
  });
  return res;
}

router.beforeEach(async (to, from, next) => {
  // 模拟已登录(实际项目中用token判断)
  const hasToken = true;
  if (hasToken) {
    if (to.path === '/login') {
      next({ path: '/' });
    } else {
      // 判断是否已获取权限
      const hasRoles = store.getters['auth/roles'].length > 0;
      if (hasRoles) {
        next();
      } else {
        try {
          // 获取权限数据
          await store.dispatch('auth/getAuth');
          const roles = store.getters['auth/roles'];
          const permissions = store.getters['auth/permissions'];
          // 过滤并添加动态路由
          const accessedRoutes = filterAsyncRoutes(asyncRoutes, roles, permissions);
          router.addRoutes(accessedRoutes);
          // 确保路由添加完成后跳转
          next({ ...to, replace: true });
        } catch (err) {
          next(`/login?redirect=${to.path}`);
        }
      }
    }
  } else {
    // 未登录则跳转登录页
    if (to.path === '/login') {
      next();
    } else {
      next(`/login?redirect=${to.path}`);
    }
  }
});

三、按钮权限控制

通过自定义指令实现按钮级别的权限控制:

1. 注册权限指令

javascript 复制代码
// src/directives/permission.js
import Vue from 'vue';
import store from '@/store';

/**
 * v-permission: 按钮权限指令
 * 使用:<button v-permission="'user:add'">新增</button>
 */
Vue.directive('permission', {
  inserted(el, binding) {
    const { value } = binding;
    const permissions = store.getters['auth/permissions'];
    // 校验权限(支持数组:v-permission="['user:add', 'user:edit']")
    if (value) {
      const hasPerm = Array.isArray(value) 
        ? permissions.some(perm => value.includes(perm)) 
        : permissions.includes(value);
      if (!hasPerm) {
        el.parentNode && el.parentNode.removeChild(el); // 无权限则移除元素
      }
    }
  }
});

/**
 * v-role: 角色权限指令
 * 使用:<button v-role="'admin'">管理员按钮</button>
 */
Vue.directive('role', {
  inserted(el, binding) {
    const { value } = binding;
    const roles = store.getters['auth/roles'];
    if (value) {
      const hasRole = Array.isArray(value) 
        ? roles.some(role => value.includes(role)) 
        : roles.includes(value);
      if (!hasRole) {
        el.parentNode && el.parentNode.removeChild(el);
      }
    }
  }
});

2. 全局引入指令

javascript 复制代码
// src/main.js
import Vue from 'vue';
import App from './App.vue';
import router from './router';
import store from './store';
import './directives/permission'; // 引入权限指令

new Vue({
  router,
  store,
  render: h => h(App)
}).$mount('#app');

四、页面中使用权限控制

javascript 复制代码
<!-- src/views/user/list.vue -->
<template>
  <div>
    <h1>用户列表</h1>
    <!-- 按钮权限控制:只有user:add权限才显示 -->
    <button v-permission="'user:add'">新增用户</button>
    <!-- 角色控制:只有admin角色才显示 -->
    <button v-role="'admin'">删除用户</button>

    <!-- 表格内容 -->
    <el-table :data="userList">
      <el-table-column label="操作">
        <template slot-scope="scope">
          <!-- 编辑权限控制 -->
          <el-button v-permission="'user:edit'" @click="editUser(scope.row)">编辑</el-button>
        </template>
      </el-table-column>
    </el-table>
  </div>
</template>

五、核心功能总结

  1. 路由权限 :通过router.addRoutes动态添加有权限的路由,结合beforeEach守卫过滤无权限页面;
  2. 按钮权限 :自定义v-permission/v-role指令,无权限时自动移除 DOM 元素;
  3. 权限存储:通过 Vuex 管理用户角色和权限码,支持从后端动态获取。

扩展建议

  • 实际项目中,权限数据需从后端接口获取(如登录后返回);
  • 可结合vue-i18n实现权限相关文案的国际化;
  • 复杂场景可增加 "数据权限"(如用户只能查看自己创建的数据),通过接口参数过滤。

这套方案轻量且易扩展,适合 Vue2 项目的基础权限管理需求。

相关推荐
华仔啊36 分钟前
CSS常用函数:从calc到clamp,实现动态渐变、滤镜与变换
前端·css
大杯咖啡37 分钟前
基于 Vue3 (tsx语法)的动态表单深度实践-只看这一篇就够了
前端·javascript·vue.js
乐无止境38 分钟前
系统性整理组件传参14种方式
前端
爱泡脚的鸡腿39 分钟前
uni-app D8 实战(小兔鲜)
前端·vue.js
睡神雾雨41 分钟前
Vite 环境变量配置经验总结
前端
咪库咪库咪41 分钟前
vue5
前端
前端缘梦41 分钟前
JavaScript核心机制:执行栈、作用域与this指向完全解析
前端·javascript·面试
Larry_zhang双栖42 分钟前
解决 Figma MCP 下载图片卡死问题:从踩坑到自研 npm 工具全记录
前端·npm·figma