Vue 3 + TypeScript + Element Plus 后台管理系统中的权限管理与鉴权
权限管理是后台管理系统中非常重要的一部分,确保用户能够基于其角色访问指定的资源,同时防止越权操作。一个完善的权限管理方案应该包括多层次的权限控制,从 Token 鉴权 到 菜单、路由、按钮权限控制,并且要确保系统的灵活性和扩展性。以下是基于 Vue 3 + TypeScript + Element Plus 的权限管理的详细技术方案。
1. Token 鉴权与权限列表的缓存
1.1 Token 鉴权
Token 鉴权是前后端分离应用的常见认证方式。通常,用户登录后,后端会根据用户的身份信息生成一个 Token(如 JWT),并返回给前端。前端将该 Token 保存在浏览器中(如 localStorage
或 sessionStorage
),并在每次发起请求时通过 HTTP 请求头携带该 Token,后端验证 Token 的有效性,判断是否允许访问对应的资源。
登录过程
- 用户提交用户名和密码进行登录。
- 后端验证用户名和密码的正确性,如果验证通过,生成 Token(如 JWT)并返回给前端。
- 前端将 Token 存储在
localStorage
或sessionStorage
中,并在后续请求时通过Authorization
请求头传递 Token。 - 后端每次收到请求时,验证 Token 是否有效,并根据验证结果返回相应的资源。
示例代码:获取 Token
// 登录成功后获取 token 并存储
const login = async (username: string, password: string) => {
const response = await axios.post('/api/login', { username, password });
const token = response.data.token;
localStorage.setItem('token', token);
};
// 请求拦截器:在每个请求中附带 Token
axios.interceptors.request.use(
(config) => {
const token = localStorage.getItem('token');
if (token) {
config.headers['Authorization'] = `Bearer ${token}`;
}
return config;
},
(error) => {
return Promise.reject(error);
}
);
1.2 权限列表的缓存
为了减少每次请求时都需要重新从后台获取权限数据,前端通常会缓存用户的权限列表(如角色权限、路由权限、菜单权限等)。缓存可以存储在 Vuex 或 Pinia 状态管理工具中,或者 localStorage
/ sessionStorage
中。
缓存的数据结构
routes
:用户可访问的路由列表。menus
:用户可访问的菜单项。buttons
:用户可执行的按钮操作。
// 角色权限和路由权限的缓存存储
const storePermissions = (permissions: Permission[]) => {
const routes = permissions.filter(p => p.type === 'menu').map(p => p.code);
const buttons = permissions.filter(p => p.type === 'button').map(p => p.code);
// 缓存到 localStorage
localStorage.setItem('routes', JSON.stringify(routes));
localStorage.setItem('buttons', JSON.stringify(buttons));
};
2. 菜单权限与路由权限控制
2.1 菜单权限
菜单权限控制通常依赖于用户的角色,系统会根据用户权限动态生成菜单。前端根据权限列表渲染相应的菜单项。
步骤:
- 后端返回用户角色的权限列表(包括菜单权限)。
- 前端根据该权限列表动态渲染菜单项。
- 如果用户没有该权限,菜单项不会显示。
示例代码:动态菜单渲染
<template>
<el-menu>
<el-menu-item v-for="item in menuItems" :key="item.code" :index="item.code">
<router-link :to="item.path">{{ item.name }}</router-link>
</el-menu-item>
</el-menu>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue';
import { usePermissionStore } from '@/stores/permission';
const menuItems = ref([]);
onMounted(() => {
const permissionStore = usePermissionStore();
menuItems.value = permissionStore.routes.filter(route => route.type === 'menu');
});
</script>
2.2 路由权限控制
路由权限控制通过路由守卫(beforeEach
)来实现。系统会根据用户的权限来动态加载路由,并阻止用户访问无权限的页面。
步骤:
- 根据用户权限动态生成路由。
- 在路由守卫中,验证用户是否有权限访问目标路由。
示例代码:路由权限控制
import { createRouter, createWebHistory } from 'vue-router';
import { usePermissionStore } from './stores/permission';
const routes = [
{
path: '/dashboard',
name: 'Dashboard',
component: () => import('@/views/Dashboard.vue'),
meta: { permission: 'view_dashboard' },
},
{
path: '/users',
name: 'Users',
component: () => import('@/views/Users.vue'),
meta: { permission: 'view_users' },
},
];
const router = createRouter({
history: createWebHistory(),
routes,
});
router.beforeEach((to, from, next) => {
const permissionStore = usePermissionStore();
const requiredPermission = to.meta.permission;
if (requiredPermission && !permissionStore.routes.includes(requiredPermission)) {
next({ name: 'Unauthorized' });
} else {
next();
}
});
export default router;
3. 按钮权限控制
按钮权限控制是指对于页面中的每个操作按钮(如编辑、删除等),根据用户权限来决定是否显示或者是否可点击。
步骤:
- 用户的权限列表中包含具体的按钮权限标识。
- 根据权限控制按钮的显示与隐藏。
示例代码:按钮权限控制
<template>
<el-button v-if="hasPermission('edit_user')" @click="editUser">编辑</el-button>
<el-button v-if="hasPermission('delete_user')" @click="deleteUser">删除</el-button>
</template>
<script setup lang="ts">
import { usePermissionStore } from '@/stores/permission';
const permissionStore = usePermissionStore();
const hasPermission = (permission: string) => {
return permissionStore.buttons.includes(permission);
};
</script>
4. 数据权限控制
数据权限控制是指用户访问的具体数据也需要根据权限进行筛选。例如,一个管理员可以查看所有用户的数据,而普通用户只能查看自己的数据。
4.1 数据权限设计
- 后端根据用户的角色和权限筛选数据。
- 前端发起请求时,附带用户的权限信息,后端根据权限返回数据。
4.2 示例代码:请求数据时附带权限
const getUserData = async () => {
const response = await axios.get('/api/user-data', {
params: {
permission: localStorage.getItem('role_permission'),
},
});
return response.data;
};
5. 总结
通过结合 Token 鉴权 和基于角色的 权限管理,可以实现灵活而高效的前端权限控制。整个系统的权限控制包括:
- Token 鉴权:验证用户身份,确保合法用户访问资源。
- 菜单权限:动态生成用户可访问的菜单项。
- 路由权限:控制用户能访问的路由。
- 按钮权限:控制用户对页面中按钮的操作权限。
- 数据权限:通过 API 请求,控制用户能访问的具体数据。
这种设计方案能够有效地管理和控制不同角色、不同权限的用户访问,同时保持前端与后端的灵活扩展性。