前端权限模型是指在前端应用中,根据用户身份、角色或权限来控制页面访问、功能操作和数据展示的机制。常见的权限模型包括 RBAC(基于角色的访问控制) 和 ABAC(基于属性的访问控制)。
一、常见权限模型分类
模型 | 名称 | 描述 |
---|---|---|
RBAC | 基于角色的访问控制(Role-Based Access Control) | 用户属于一个或多个角色,每个角色拥有权限 |
ABAC | 基于属性的访问控制(Attribute-Based Access Control) | 权限由用户、资源、环境等属性动态决定 |
ACL | 访问控制列表(Access Control List) | 每个资源都有一个允许访问的用户/角色列表 |
IAM | 身份与访问管理(Identity and Access Management) | 综合性权限管理系统,常用于企业级系统 |
二、前端权限控制层级
1. 路由级别权限
- 控制用户能否访问某个页面。
- 实现方式:在路由配置中添加
meta.roles
或meta.permission
字段,在导航守卫中进行判断。
{
path: '/admin',
name: 'Admin',
component: AdminView,
meta: { roles: ['admin'] }
}
导航守卫示例:
router.beforeEach((to, from, next) => {
const userRoles = store.getters.userRoles;
const requiredRoles = to.meta.roles;
if (requiredRoles && !requiredRoles.some(role => userRoles.includes(role))) {
next('/unauthorized');
} else {
next();
}
});
2. 组件/按钮级别权限
- 控制用户是否能看到某个按钮、菜单项或组件。
- 实现方式:自定义指令、高阶组件、条件渲染。
自定义指令实现
// src/directives/permission.js
export default {
mounted(el, binding, vnode) {
const { value } = binding;
const roles = vnode.context.$store.getters.userRoles;
if (value && !roles.includes(value)) {
el.parentNode.removeChild(el);
}
}
}
使用方式:
<template>
<button v-permission="'admin'">删除</button>
</template>
3. API 接口级别权限
- 控制用户是否有权限调用某个接口。
- 实现方式:在请求拦截器中校验 token、role 等信息。
axios.interceptors.request.use(config => {
const role = store.getters.userRole;
if (config.url.includes('/api/admin') && role !== 'admin') {
return Promise.reject(new Error('无权限访问'));
}
return config;
});
4. 数据粒度权限
- 控制用户只能看到自己有权限的数据(如部门、项目、客户等)。
- 实现方式:后端返回数据时带权限标识,前端按字段过滤。
例如:
{
"name": "张三",
"salary": "保密",
"permissions": ["view_profile", "edit_profile"]
}
前端逻辑:
if (user.permissions.includes('view_salary')) {
showSalary(user.salary);
} else {
showSalary('权限不足');
}
三、权限模型设计建议
场景 | 推荐模型 |
---|---|
中小型后台系统 | RBAC + 路由/按钮权限 |
多租户 SaaS 系统 | RBAC + ABAC(结合组织、用户属性) |
动态权限变更频繁 | ABAC 或 IAM 集成 |
数据隔离要求高 | 后端控制 + 前端字段级控制 |
快速开发后台系统 | 使用 RBAC + 路由懒加载 + 权限指令 |
四、Vue + RBAC 典型实现结构
1. 路由配置文件
const routes = [
{
path: '/dashboard',
name: 'Dashboard',
component: DashboardView,
meta: { roles: ['user', 'admin'] }
},
{
path: '/admin',
name: 'AdminPanel',
component: AdminView,
meta: { roles: ['admin'] }
}
]
2. Vuex/Pinia 存储用户角色
// store/index.js
state: {
user: null,
roles: []
}
actions: {
login({ commit }, credentials) {
api.login(credentials).then(res => {
commit('SET_USER', res.user);
commit('SET_ROLES', res.user.roles);
});
}
}
3. 导航守卫权限判断
router.beforeEach((to, from, next) => {
const isAuthenticated = store.getters.isAuthenticated;
const requiredRoles = to.meta.roles;
if (to.meta.requiresAuth && !isAuthenticated) {
next('/login');
} else if (requiredRoles && !requiredRoles.some(r => store.getters.roles.includes(r))) {
next('/unauthorized');
} else {
next();
}
});
五、建议
技术点 | 建议做法 |
---|---|
路由权限 | 使用 meta.roles + 导航守卫 |
按钮权限 | 使用自定义指令或封装权限组件 |
接口权限 | 请求拦截器中加入权限判断 |
数据权限 | 后端返回字段控制 + 前端字段过滤 |
动态权限 | 登录后根据角色动态注册路由 |
安全性 | 所有权限校验应以前端+后端双重验证为准 |