引言
在构建企业级Web应用时,菜单权限控制很关键。前端层面实现菜单权限控制,确保系统安全性的同时提升用户体验。
@[一、权限模型和数据结构]
##一、权限模型和数据结构
权限模型:常见的权限模型有基于角色的权限控制(RBAC,Role-Based Access Control),即用户通过角色与权限关联,角色再与具体的菜单项绑定。菜单结构一般采用树形结构,方便递归渲染与权限过滤。
数据对接:前端通过与后端API交互,获取当前登录用户的角色及其所拥有的菜单权限数据。这部分数据通常包括菜单ID、名称、URL、父节点ID以及是否可见、是否可访问等权限标识。
数据处理:拿到权限数据后,前端需要将其转换为易于操作的数据结构,例如数组或对象。可以按照菜单层级构建嵌套数组,便于递归生成菜单。
二、前端权限控制实现策略
- 渲染前过滤
在渲染菜单组件前,根据用户权限数据对原始菜单数据进行筛选,去除无权限访问的菜单项。这是一种主动过滤的方式,可以减少无用DOM元素的生成,降低内存占用。
function filterMenusByPermission(menus, permissions) {
return menus.filter(menu => permissions.includes(menu.id) && menu.visible);
}
- 渲染时控制
在菜单组件的渲染函数内部,针对每个菜单项判断其权限属性,决定是否渲染。这种方式下,即使用户没有权限的菜单项也会被创建成DOM元素,但在最终呈现时会被隐藏。
function MenuItem({ menu }) {
if (!menu.accessible) return null; // 权限不足,不渲染此菜单项
return <div>{menu.name}</div>;
}
function MenuList({ menus }) {
return (
<ul>
{menus.map(menu => (
<MenuItem key={menu.id} menu={menu} />
))}
</ul>
);
}
- 动态路由控制
在使用了路由系统的项目中,还可以结合路由配置实现权限控制。为每个路由配置对应的权限标识,然后在路由守卫(如Vue中的beforeEach钩子函数)中进行拦截和跳转处理。
router.beforeEach((to, from, next) => {
const hasPermission = checkUserPermission(to.meta.permission); // 自定义校验函数
if (hasPermission) {
next();
} else {
next({ name: 'Unauthorized' }); // 无权限时重定向至未经授权页面
}
});
三、实时权限变更应对
考虑到权限可能在用户使用过程中动态变更,前端还需要监听权限变更事件,及时刷新菜单数据和路由控制。例如,可以通过WebSocket、EventBus或定期轮询等方式接收来自后端的权限更新通知。
四:示例-使用Vue3语法实现前端菜单权限控制
<template>
<ul class="menu-list">
<li v-for="menu in filteredMenus" :key="menu.id">
<router-link :to="menu.path">{{ menu.name }}</router-link>
<ul v-if="menu.children">
<li v-for="child in menu.children" :key="child.id">
<router-link :to="child.path">{{ child.name }}</router-link>
</li>
</ul>
</li>
</ul>
</template>
<script setup lang="ts">
import { ref, computed, useRouter } from 'vue';
import { useStore } from '@/stores/index'; // 存在一个Vuex Store
// 从Vuex Store中获取用户权限和菜单数据
const store = useStore();
const userPermissions = ref<string[]>(store.getters.getUserPermissions);
const menuData = ref<any[]>(store.getters.getMenuData);
// 计算过滤后的菜单
const filteredMenus = computed(() => {
return menuData.value.filter(menu =>
userPermissions.value.some(permission => menu.permission.includes(permission)) &&
menu.visible
).map(menu => ({
...menu,
children: filterChildren(menu.children),
}));
});
const filterChildren = (children: any[] = []) => {
return children.filter(child =>
userPermissions.value.some(permission => child.permission.includes(permission)) &&
child.visible
);
};
// 动态路由控制
const router = useRouter();
router.beforeEach(async (to, from, next) => {
const hasPermission = to.meta.permission?.some(permission =>
userPermissions.value.includes(permission)
);
if (hasPermission || !to.meta.permission?.length) {
next();
} else {
next({ name: 'Unauthorized' });
}
});
</script>
首先,可以从Vuex Store中获取用户权限和菜单数据,并通过ref和computed来管理这些数据。接着,计算出用户有权限访问的菜单项,并在模板中进行渲染。
同时,也可以利用Vue Router的beforeEach全局守卫实现了动态路由权限控制。在实际项目中,请确保userPermissions和menuData是从正确的地方获取的,可能是Vuex Store,也可能是API接口。
版权归原作者 飞108 所有, 如有侵权,请联系我们删除。