Ejemplo detallado de cómo agregar elegantemente control de permisos en vue
Prólogo
En un proyecto, algunas funciones implicarán una gestión de datos importante. Para garantizar la seguridad de los datos, agregaremos permisos al proyecto para limitar las operaciones de cada usuario. Como interfaz, lo que tenemos que hacer es cooperar con los datos de permiso proporcionados por el back-end para establecer varias restricciones en la página.
Requisitos
Debido a que este es un requisito comercial en el trabajo, para mí hay dos lugares principales donde se requiere control de permisos.
La primera es la barra de menú lateral, que debe mostrarse y ocultarse.
El segundo son los distintos botones, ventanas emergentes, etc. dentro de la página.
Proceso
1. ¿Cómo obtener permisos de usuario?
Backend (lista de permisos propiedad del usuario actual) -gt; Front-end (obtenido a través de la interfaz de backend, a continuación llamamos lista de permisos del usuario actual)
2. ¿Limitar el front-end?
De acuerdo con los requisitos del producto, configure los puntos de permiso en el proyecto y luego use la Lista de permisos para encontrar si hay puntos de permiso configurados. Si los hay, se mostrará. De lo contrario, no se mostrará. desplegado.
3. ¿Qué sigue?
No más.
Eso es lo que pensé cuando recibí este requisito por primera vez. ¿Qué tiene de difícil? Simplemente obtenga la lista de permisos y luego emita un juicio. Más tarde descubrí que las necesidades reales eran mucho más complejas de lo que imaginaba.
El verdadero problema
Los requisitos anteriores mencionan que solucionamos principalmente dos problemas, la visualización de la barra de menú lateral y la operación dentro de la página.
Supongamos que tenemos una configuración de enrutamiento de este tipo (lo siguiente es solo un ejemplo):
importar VueRouter desde 'vue-router'
/* Nota: siguiente configuración Solo configuración parcial y se omite la configuración de componentes*/
export const route = [
{
ruta: '/',
nombre: 'Administrador',
etiqueta: 'Inicio'
},
{
ruta: '/ usuario ',
nombre: 'Usuario',
etiqueta: 'Usuario',
redirección: { nombre: 'UserList' },
hijos: [
{
ruta: 'lista',
nombre: 'UsuarioLista',
etiqueta: ' Usuario lista'
},
{
ruta: 'grupo',
nombre: 'Grupo de usuarios',
etiqueta: 'Grupo de Usuarios',
redirección: { nombre: 'Lista de Grupo de Usuarios' },
hijos: [
{
ruta: 'lista',
nombre: 'UserGroupList',
etiqueta: 'Lista de grupos de usuarios'
},
{
ruta: 'config',
nombre: 'UserGroupConfig',
etiqueta: 'Configuración de grupo de usuarios'
} p>
]
}
]
},
{
ruta: '/ configuración',
nombre: 'Configuración',
etiqueta: 'Configuración del sistema'
},
{ p>
ruta: '/iniciar sesión',
nombre: 'Iniciar sesión',
etiqueta: 'Iniciar sesión'
}
]
const router = new VueRouter({
rutas
})
exportar enrutador predeterminado
El Los primeros dos niveles de enrutamiento se mostrarán en la barra lateral, pero el tercer nivel no se mostrará en la barra lateral.
No es necesario considerar muchas otras cosas al configurar permisos para operaciones dentro de la página. Analizamos principalmente la barra lateral y los problemas de enrutamiento, principalmente tenemos los siguientes problemas:
<. p> Cuándo obtener la Lista de permisos y cómo almacenar la Lista de permisosCuando todas las subrutas no tienen permisos, no deben mostrarse (por ejemplo: cuando ni la lista de usuarios ni el grupo de usuarios tienen permisos, el usuario no debe mostrarse en la barra lateral)
Cuando la ruta de redireccionamiento predeterminada no tiene permiso, debe buscar una redirección en los niños que tenga permiso (por ejemplo: la ruta del usuario redirige a la ruta de la lista de usuarios. Si la lista de usuarios no tiene permiso, debe redirigir a la ruta del grupo de usuarios)
Cuando el usuario ingresa directamente una URL no autorizada, debe saltar a una página no autorizada o realizar otras operaciones. (Restricciones de enrutamiento)
Ahora resolveremos los problemas anteriores uno por uno.
Cuándo obtener permisos y dónde almacenarlos y restricciones de enrutamiento
Los obtengo aquí antes de cada enrutador, y la lista de permisos obtenida se almacena en vuex.
El motivo es considerar las restricciones de enrutamiento y facilitar el uso de listas de permisos en proyectos posteriores. El siguiente es un ejemplo de implementación:
Primero, agregamos la configuración de permisos. el enrutador:
//A continuación solo se muestra parte de la configuración
{
ruta: '/usuario',
nombre : 'Usuario',
etiqueta: 'Usuario',
meta: {
permisos: ['U_1']
} ,
redirección: { nombre: 'UserList' },
hijos: [
{
ruta: 'lista',
nombre: 'Lista de usuarios',
etiqueta: 'Lista de usuarios',
meta: {
permisos: ['U_1_1']
}
},
{
ruta: 'grupo',
nombre: 'Grupo de usuarios',
etiqueta: 'Grupo de usuarios',
meta: {
permisos: ['U_1_2']
},
redirigir: { nombre: 'UserGroupList' },
hijos: [
{
ruta: 'lista',
nombre: 'UserGroupList',
etiqueta: 'Lista de grupos de usuarios',
meta: {
permisos: ['U_1_2_1']
}
},
{
ruta: 'config',
nombre: 'UserGroupConfig', p>
etiqueta: 'Configuración del grupo de usuarios',
meta: {
permisos: ['U_1_2_2']
}
} p>
]
}
]
}
Puedes ver que hemos agregado permisos a meta Sí Para facilitar la determinación de los permisos de router.beforeEch, los permisos se establecen en una matriz porque una página puede implicar múltiples permisos.
A continuación configuramos router.beforeEach:
//Introduce el vuex del proyecto
importar tienda desde '@/store'
//Introduce una función para determinar si se concede el permiso
import { includePermission } from '@/utils/permission'
router.beforeEach(async (a, desde, siguiente) =gt; {
// Primero determine si es un inicio de sesión. Solo después de iniciar sesión puede obtener permisos. No se escribirá cómo determinar el inicio de sesión.
if (!isLogin) {
intente {
// Obtenga la lista de permisos aquí
await store.dispatch('getPermissionList')
// Determine si el la página actual tiene permisos aquí
const { permisos } = to.meta
if (permisos) {
const hasPermission = includePermission(permisos)
if (!hasPermission) siguiente ({ nombre: 'NoPermission' })
}
siguiente()
}
} else {
next({ name: 'Login' })
}
})
Podemos ver que necesita un método para determinar los permisos amp vuex. La getPermissionList es la siguiente:
// @/store
exportar estado predeterminado {
: { p>
lista de permisos: [] p>
},
mutaciones: {
actualizaciónLista de permisos: (estado, carga útil) =gt;
state.permissionList = carga útil
}
},
acciones: {
getPermissionList: async ({ estado, confirmación }) =gt; {
// Esto es para evitar adquisiciones repetidas
if (state.permissionList.length) return
// El método de envío de la solicitud se omite
const list = await api.getPermissionList()
commit('updatePermissionList', list)
}
}
}
// @/utils/permission
importar tienda desde '@/store'
/**
* Determine si tiene permiso
* @param {Arraylt; stringgt;} permisos: los permisos se determinarán
Lista limitada
*/
función includePermission (permissions = []) {
// Si el permiso para ser juzgado aquí no está establecido, significa que no se requiere permiso, devuelve verdadero directamente
si (!permissions.length) devuelve verdadero
const permisoList = store.state.permissionList
devuelve !!permisos .find(permission =gt; permisoList.includes(permission))
}
Problema de redirección
Arriba hemos resuelto la configuración básica del enrutamiento y cómo Para obtener permisos y cómo restringirlos, lo siguiente que tenemos que afrontar es el problema de la redirección.
Esto puede estar relacionado con la estructura de nuestro proyecto en sí. Hay subniveles debajo de la barra lateral de nuestro proyecto, que se muestran mediante el cambio de pestaña en la figura siguiente. Normalmente, la página será redirigida. después de hacer clic en administración de medicamentos, vaya a la página de cambio de pestaña de administración de entrada. Sin embargo, cuando la administración de entrada no tiene permiso, se debe redirigir directamente a la interfaz de administración de salida.
Entonces, para lograr el efecto anterior, necesito reescribir la redirección del enrutador para que pueda determinarse dinámicamente (porque no conozco la lista de permisos del usuario actual al configurar la ruta)
Luego verifiqué la documentación de vue-router y descubrí que la redirección puede ser un método para resolver el problema de la redirección.
Instrucciones de redireccionamiento en vue-router, de acuerdo con las instrucciones podemos reescribir el redireccionamiento de la siguiente manera:
// Necesitamos introducir un método para determinar los permisos
importar { includePermission } de ' @/utils/permission'
const niños = [
{
ruta: 'lista',
nombre: 'Lista de usuarios',
etiqueta: 'Lista de usuarios',
meta: {
permisos: ['U_1_1']
}
},
{
ruta: 'grupo',
nombre: 'Grupo de usuarios',
etiqueta: 'Grupo de usuarios',
meta: {
permisos: ['U_1_2']
}
}
>]
const routeDemo = {
ruta: '/usuario',
nombre: 'Usuario',
etiqueta: 'usuario',
redirigir: (a) =gt; {
if (includePermission(children[0].meta.permissions)) return { nombre: niños[0].nombre }
if (includePermission(children[1].meta.permissions)) return { nombre: niños[1].nombre }
}, p>
niños
}
Aunque el problema está solucionado, nos resulta muy complicado anotarlo así, y tenemos que modificar la configuración del router, por lo que utilice un método para generarlo:
/ / @/utils/permission
/**
* Crear función de redireccionamiento
* @param {Objeto} redirección - objeto de redirección
* @param {string} redirección.nombre - el nombre del componente redirigido
* @param {Arraylt;anygt;} niños - el niño list
*/
function createRedirectFn (redirect = {}, Children = []) {
// Evite hacer que el caché sea demasiado grande, solo conserve el nombre y permisos de los niños
const permisoChildren = niños .map(({ nombre = '', meta: { permisos = [] } = {} }) =gt; ({ nombre, permisos }))
return function (to) {
// No debes filtrar fuera de la función de retorno aquí, porque los permisos se obtienen de forma asincrónica
const hasPermissionC
hildren = permisoChildren.filter(item =gt; includePermission(item.permissions))
// Nombre de redireccionamiento completo predeterminado
const defaultName = redirección.nombre || >
// Si la redirección predeterminada no tiene permiso, seleccione la primera ruta con permiso de los niños para la redirección
const firstPermissionName = (hasPermissionChildren[0] || { name : '' }). name
// Determina si es necesario modificar la redirección predeterminada
const saveDefaultName = !!hasPermissionChildren.find(item =gt; item.name === defaultName amp; defaultName)
if (saveDefaultName) devuelve { nombre: defaultName }
si no, devuelve firstPermissionName? { nombre: firstPermissionName }: redirigir
}
}
Luego podemos reescribirlo como:
// Necesitamos introducir un método para determinar los permisos
importar { includePermission, createRedirectFn } de '@/ utils/permission'
const niños = [
{
ruta: 'lista',
nombre: 'Lista de usuarios',
etiqueta: 'Lista de usuarios',
meta: {
permisos: ['U_1_1']
}
},
{
ruta: 'grupo',
nombre: 'Grupo de usuarios',
etiqueta: 'Grupo de usuarios' ,
meta: {
permisos: ['U_1_2']
}
}
]
const routeDemo = {
ruta: '/usuario',
nombre: 'Usuario',
etiqueta: 'Usuario',
redirección: createRedirectFn({ name: 'UserList' }, Children),
Children
}
Esto es un poco más simple. pero todavía necesito modificar las rutas una por una, así que escribí otro método para configurar enrutadores de forma recursiva y reescribir sus redirecciones:
// @/utils/permission p>
/**
* Crear configuración de enrutamiento con permisos (multinivel)
* @param {Object} config - objeto de configuración de enrutamiento
* @param {Object
} config.redirect: debe ser uno de los hijos y usar el nombre
*/
función createPermissionRouter ({ redirección, hijos = [], ...otros }) {< / p>
const needRecursion = !!children.length
if (needRecursion) {
return {
...otros,
redirección: createRedirectFn(redirect, niños),
niños: niños.map(item =gt; createPermissionRouter(item))
}
} else {
devolver {
...otros,
redirigir
}
} p >
}
De esta manera solo necesitamos agregar dicha capa de funciones a la configuración del enrutador más externo:
importar { createPermissionRouter } desde '@/utils /permission'
const routeConfig = [
{
ruta: '/usuario',
nombre: 'Usuario',
etiqueta: 'Usuario',
meta: {
permisos: ['U_1']
},
redirección : { nombre: 'UserList' },
niños: [
{
ruta: 'lista',
nombre: ' UserList',
etiqueta: 'UserList',
meta: {
permisos: ['U_1_1']
} p>
},
{
ruta: 'grupo',
nombre: 'Grupo de usuarios',
etiqueta: 'Grupo de usuarios',
meta: {
permisos: ['U_1_2']
},
redirección: { nombre: 'UserGroupList' },
hijos: [
{
ruta: 'lista',
nombre: 'UserGroupList',
etiqueta: 'Lista de grupos de usuarios',
meta: {
permisos: ['U_1_2_1']
}
},
{
ruta: 'config',
nombre: 'UserGroupConfig',
etiqueta: 'Usuario configuración del grupo',
meta: {
permisos
: ['U_1_2_2']
}
}
]
}
]
}
]
exportar rutas const = rutasConfig.map(item =gt; createPermissionRouter(item))
enrutador const = new VueRouter({
rutas
})
exportar enrutador predeterminado
Por supuesto, hay otra ventaja al escribir de esta manera. De hecho, usted. no es necesario configurar la redirección. Esto redirigirá automáticamente a la primera ruta autorizada para niños
Problema de visualización de la barra lateral
Nuestro proyecto utiliza la configuración de la ruta para generar la barra lateral. Por supuesto, se agregarán algunos otros parámetros para mostrar el nivel de visualización y otros problemas. No escribiré el código específico aquí sobre cómo resolver el problema de que los niños en la barra lateral no se muestren sin permiso.
Mi idea aquí es actualizar la configuración de enrutamiento a vuex y luego leer la configuración de la barra lateral desde la configuración en vuex.
Dado que este lugar implica muchas modificaciones e implica negocios, no sacaré el código. Puedes experimentarlo tú mismo.
Métodos para facilitar la implementación de puntos de permiso en equipo
Hemos resuelto la mayoría de los problemas de permisos anteriores, pero todavía hay muchas implementaciones de puntos de permiso que involucran lógica empresarial, por lo que, por el bien de otros miembros del equipo Las personas pueden implementar permisos en varias páginas de manera elegante y sencilla. He proporcionado las siguientes formas de implementar permisos en el proyecto:
Establecer directamente en la plantilla mediante el comando v-permission
lt;div v-permission="['U_1']"gt;lt;/divgt;
Juzgado por el método global this.$permission, porque algunos permisos no están en la plantilla
{
hasPermission () {
// Determina si tienes permiso mediante el método $permission
return this.$permission (['U_1_1' , 'U_1_2'])
}
}
Cabe señalar aquí que para que el valor de retorno de $permission método a monitorear, el juicio debe basarse en esto.$sto