一、权限控制
随着前端技术的不断发展,越来越多的前端框架被使用在 Web 应用程序中,其中尤为出色的一个就是 Vue。Vue 是一个易于理解并且使用方便的框架,它被广泛地应用于 Web 应用程序的开发中。在大多数 Web 应用程序中,权限控制是至关重要的一部分,如何在 Vue 中进行权限控制就成为了一个十分关键的问题。
权限控制是一个很重要的概念,在 Web 应用程序中尤其重要。简单地说,权限控制就是将用户分为不同的分类,为每个分类分配相应的用户权限。这样,用户就只能访问他们所允许的内容了。权限控制可以提高应用程序的安全性和稳定性,使数据更加安全可靠。
在 Vue 中进行权限控制,通常有两种方式:第一种是在路由层面进行控制,第二种是在组件层面进行控制。
用户登录后该用户的角色与权限信息会一同返回给前端,前端将这些信息存储到状态管理里备用即可。
- 这里使用pinia存储当前用户的角色及权限。你可以根据实际情况进行相应的调整。
- store/index.js
import { defineStore } from 'pinia' import { ref } from 'vue'; export const userPermissionsStore = defineStore('userPermissions', () => { // 角色 const roles = ref('admin') // 权限 const userPermissions = ref([]) //是否登录 const isLogin = ref(false) // 设置状态(传入的权限信息赋值给该状态) const setUserPermissions = (params) => { userPermissions.value = params } return { isLogin, userPermissions, roles, setUserPermissions } })
二、路由层面控制
在路由层面进行控制,可以在路由的元数据 meta 中设置用户权限,然后可以在路由守卫函数中进行校验。如果当前用户的权限符合该路由的要求,则策略继续进行,否则将导航到其他页面。
路由的元数据 meta 中设置了 requireAuth 和 roles 两个属性,requireAuth 表示该路由需要用户登录才能访问,roles 表示受访问限制的角色。可以在 beforeEach 路由守卫函数中校验用户权限,如果用户有访问该路由的权限,则进入页面,否则跳转到其他页面。这样,就可以在路由层面进行权限控制了。
import { createRouter, createWebHashHistory } from 'vue-router' import { userPermissionsStore } from '@/store/index' import { storeToRefs } from 'pinia' let routes = [{ path: '/home', // 路径 name: 'home', // 路由名称 component: () => import('../views/home.vue'), meta: { requireAuth: true, // 需要用户权限 roles: ['admin', 'guest'] // 受访问限制的角色 } }, { path: '/login', name: 'login', component: () => import('../views/login.vue') }, { path: '/denied', name: 'denied', component: () => import('../views/denied.vue') }] const router = createRouter({ history: createWebHashHistory(), routes }) // 添加路由前置守卫 router.beforeEach((to, from, next) => { const store = userPermissionsStore() // 获取当前登录状态及用户角色 const { isLogin, roles } = storeToRefs(store) // 判断该路由是否需要登录权限 if (to.meta.requireAuth) { // 如果需要,则校验用户是否已经登录 if (isLogin.value) { // 判断当前用户是否有访问该路由的权限 if (to.meta.roles.includes(roles.value)) { next() // 用户有访问权限,直接进入页面 } else { next('/denied') // 跳转到其他页面 } } else { // 如果用户未登录,则跳转到登录页面 next('/login') } } else { next() // 如果不需要登录权限,直接进入页面 } }); export default router
三、组件层面控制
1、使用自定义指令
可以利用 Vue 的指令来控制组件的显示和隐藏。例如,可以为每个组件设置一个权限属性,然后在指令中判断当前用户是否有访问该组件的权限,如果有,则显示组件,否则隐藏组件。利用 v-if 指令来判断当前用户是否有访问该组件的权限,并根据权限设置组件的显示和隐藏。
<template> <el-button type="success" plain v-permission="'sys:user:add'">添加用户1</el-button> </template> <script setup> import { userPermissionsStore } from '@/store/index' import { storeToRefs } from 'pinia' const store = userPermissionsStore() const { userPermissions } = storeToRefs(store) const vPermission = { mounted(el, binding) { const requiredPermission = binding.value; if (!userPermissions.value.includes(requiredPermission)) { el.style.display = 'none'; } } } </script>
2、使用方法控制
<template> <el-button type="primary" plain v-if="hasPermission('sys:user:add')">添加用户1</el-button> </template> <script setup> import { userPermissionsStore } from '@/store/index' import { storeToRefs } from 'pinia' const store = userPermissionsStore() const { userPermissions } = storeToRefs(store) const hasPermission = (permission) => { return userPermissions.value.includes(permission); } </script>
3、封装一个权限控制组件来实现组件层面控制权限
3.1、组件页面 Authority.vue
<template> <slot v-if="showSlot" :userPermissions="userPermissions"></slot> </template> <script setup> import { computed } from 'vue'; import { storeToRefs } from 'pinia' import { userPermissionsStore } from '@/store/index' const store = userPermissionsStore() // 为了从 store 中提取属性时保持其响应性,你需要使用 storeToRefs() const { userPermissions } = storeToRefs(store) const props = defineProps({ // 需要的权限 permissions: { type: [String, Array] } }); const showSlot = computed(() => { if (!props.permissions) { return true } if (!userPermissions.value) { return false } if (Array.isArray(props.permissions)) { return props.permissions.every(p => { return userPermissions.value.includes(p) }) } else { return userPermissions.value.includes(props.permissions) } }) </script> <style scoped> </style>
3.2、使用页面 app.vue
<template> <el-select v-model="value" placeholder="请选择" @change="change" style="width: 300px; margin: 20px 0;"> <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" /> </el-select> <div> <!-- 这里可以根据返回的权限,做自己想判断的事情 --> <Authority> <template #default="{ userPermissions }"> <el-button :disabled="!userPermissions.includes('sys:user:delete')" type="primary">禁用用户1</el-button> </template> </Authority> <!-- 传入组件所需要的权限 --> <Authority permissions="sys:user:view"> <el-button>查询用户2</el-button> </Authority> <Authority permissions="sys:user:update"> <el-button type="success">修改用户3</el-button> </Authority> <Authority permissions="sys:user:delete"> <el-button type="info">删除用户4</el-button> </Authority> <Authority permissions="sys:user:add"> <el-button type="warning">添加用户5</el-button> </Authority> <Authority :permissions="['sys:user:update', 'sys:user:delete']"> <el-button type="danger">禁用用户6</el-button> </Authority> </div> </template> <script setup> import Authority from '@/components/Authority.vue' import { ref } from 'vue' const value = ref('') const options = [{ value: '0', label: 'admin', permissions: ["sys:user:view", "sys:user:update", "sys:user:delete", "sys:user:add"] }, { value: '1', label: 'editor', permissions: ["sys:user:view", "sys:user:update", "sys:user:add"] }, { value: '2', label: 'guest', permissions: ["sys:user:view"] }] import { userPermissionsStore } from '@/store/index' const store = userPermissionsStore() // 作为 action 的 setUserPermissions 可以直接解构 const { setUserPermissions } = store const change = (e) => { setUserPermissions(options[e].permissions) } </script> <style scoped> </style>
3.3、效果预览
这里使用el-select下拉框切换用户角色,存储pinia,是为了演示不同用户,不同的角色权限切换效果。