DEV Community

Genaro Hernández
Genaro Hernández

Posted on • Updated on

Roles y permisos en Laravel Jetstream con Inertia.js

En cualquier proyecto es muy común la utilización de roles y permisos. Existen muchos ejemplos de realizar esta funcionalidad en un proyecto Laravel con blade o Laravel con Livewire. Pero ¿cómo agregar roles y permisos en Laravel Jetstream con InertiaJS? 🤔

En este tipo de proyectos en el cual se combina el backend con el frontend es necesario que la tecnología frontend conozca al usuario autenticado incluyendo que roles y permisos tiene. Por lo tanto, InertiaJS nos facilita nativamente obtener los roles y permisos. 😀

En tu backend debes de construir la funcionalidad de roles y permisos, puedes utilizar cualquier paquete; en lo personal utilizo Laravel Permission, si deseas un artículo respecto a cómo realizar esta funcionalidad, solo dejen un comentario solicitándolo.

Continuemos, en un proyecto con InertiaJS debemos ubicar el siguiente middleware: HandleInertiaRequests.php. Dentro del método share debemos de realizar algunas modificaciones.

public function share(Request $request)
{
    return array_merge(parent::share($request), [
        'auth' => function() {
            $user = auth()->user();
                return $user ? [
                    'roles' => $user->getRoleNames(),
                    'permissions' => $user->getAllPermissions()->pluck('name')
            ] : null;
        }
    ]);
}
Enter fullscreen mode Exit fullscreen mode

Explico el código, si el usuario esta autenticado entonces que retorne los roles y permisos que el usuario tiene asignado; si no está autenticado que retorne nulo.

Ahora en un componente vue, dentro del template escribimos lo siguiente

<template>
    <div>
        {{ $page.props.auth.roles[0] === 'admin' ? true : false }}
    </div>
</template>
Enter fullscreen mode Exit fullscreen mode

Con este pequeño código lo que hacemos es verificar si el primer rol del usuario es admin, en este caso es verdadero, lo que se podría hacer entonces es:

<template>
    <div v-if="$page.props.auth.roles[0] === 'admin'">
        Solo el admin puede ver.
    </div>
</template>
Enter fullscreen mode Exit fullscreen mode

Espero que sea util esta forma de poder utilizar los roles y permisos en su proyecto Laravel con Inertia.js 🤭

FIN

Na... Sigamos codeando 💪, en el caso que un usuario tenga más de un rol y varios permisos sería muy difícil adivinar que rol tiene y por tanto establecer las restricciones que se desea.

Para resolver este problema, haremos uso de un paquete llamado Vue Gates, primero lo instalaremos utilizando yarn o npm:
yarn add vue-gates o npm i vue-gates --save. En su documentación en la sección Usage/Server Side Rendering/The asyncData Method tiene un ejemplo de cómo aplicarlo en nuestro proyecto:

export default {
  async asyncData ({ $axios, $gates }) {
    const [roles, permissions] = await Promise.all([
      $axios.$get('/api/roles'),
      $axios.$get('/api/permissions')
    ])

    $gates.setRoles(roles)
    $gates.setPermissions(permissions)
  }
}
Enter fullscreen mode Exit fullscreen mode

Con este ejemplo de la documentación podemos adaptarlo en cada página de vue; lo único malo es que se tendrá que repetir el código en cada página y eso no es una buena práctica, lo ideal es reutilizar el código. Entonces, por sencilles vamos a crear un plugin en vue.

Creamos el siguiente archivo en la ruta resource/js/Plugins/Permissions.js.

import { usePage } from '@inertiajs/inertia-vue3'
export default {
    install: (app) => {
        app.mixin({
            mounted(){
                let authRoles = usePage().props.value.auth;
                let authPermissions;
                if(authRoles !== null){
                    authRoles = usePage().props.value.auth.roles;
                    authPermissions = usePage().props.value.auth.permissions;
                    this.$gates.setRoles(authRoles);
                    this.$gates.setPermissions(authPermissions);
                }
            }
        })
    }
}
Enter fullscreen mode Exit fullscreen mode

Lo primero que haremos es importar usePage desde InertiaJS, lo cual nos permite hacer uso de los props, ¿recuerdan que en el middleware HandleInertiaRequest.php agregamos 'auth' para verificar si el usuario autenticado tiene roles y permisos?, lo que realmente hicimos fue que el 'auth' se cargue ni bien se inicia el aplicativo Laravel, y por lo tanto estará disponible en toda nuestra aplicación.

Ahora, también inicializamos dos variables uno para los roles y el otro para los permisos, en el authRoles le asignamos la autenticación del usuario, solo queremos saber si esta autenticado o no, en el authPermissions solo lo declaramos.

Vamos a registrar el plugin que hemos creado para poder utilizarlo globalmente en el archivo app.js.

import { createApp, h } from 'vue';
import { createInertiaApp } from '@inertiajs/inertia-vue3';
import VueGates from 'vue-gates';
import Permissions from './Plugins/Permissions';
const appName = window.document.getElementsByTagName('title')[0]?.innerText || 'Laravel';
createInertiaApp({
    title: (title) => `${title} - ${appName}`,
    resolve: (name) => require(`./Pages/${name}.vue`),
    setup({ el, app, props, plugin }) {
        return createApp({ render: () => h(app, props) })
            .use(plugin)
            .use(VueGates)
            .use(Permissions)
            .mixin({ methods: { route } })
            .mount(el);
    },
});
Enter fullscreen mode Exit fullscreen mode

Una vez que el usuario esta autenticado pasará la condicional. Y las dos variables tendrán los datos solicitados, lo cual manipulará 'vue gates' para las respectivas restricciones.

Ahora, en un componente vue utilizaremos las directivas que nos provee el paquete Vue Gates y haremos lo siguiente:

<template>
    <div v-role="'admin'">
        Solo el admin puede ver.
    </div>
</template>
Enter fullscreen mode Exit fullscreen mode

Aplicar roles y permisos en InertiaJS (que es el eje de comunicación de Laravel con VueJS) se volvió muy fácil. Si quieres conocer más directivas de este paquete solo ve a la documentación de Vue Gates. Espero que sea de mucha utilidad para los que quieren aplicar roles y permisos a sus proyectos.

Extra

En mi repositorio tengo un proyecto llamado LaraDash que tiene implementado lo que describo en este artículo.


Si este artículo te fue de mucha ayuda, no dudes en darle un ❤.

Discussion (14)

Collapse
mreduar profile image
Eduar Bastidas

Buenisimo Genaro, gracias por compartir, me ayudo mucho

Collapse
mreduar profile image
Eduar Bastidas • Edited on

Hola @genarohv Vengo aqui porque fue donde segui el tutorial para implementarlo, estoy requiriendo utilizar las directivas como funciones, por ejemplo

this.$gates.getRoles(); // ['writer']
this.$gates.hasRole('admin'); // false
Enter fullscreen mode Exit fullscreen mode

Pero esto no se puede utilizar en Vue 3 asi como asi porque ni this ni $gates son variables en el nuevo Composition API de Vue 3

¿Tienes alguna idea de como implementarlo?

Collapse
eduloper profile image
Genaro Hernández Author

Hola Eduar, puedes inspeccionar o descargar el código en GitHub, esta basado en Vue 3.2, recuerda que para que funcione VueGates debes de crear un mixin (plugin). Espero que te sirva de guía el repositorio.

Thread Thread
mreduar profile image
Eduar Bastidas

Hello, en todo el proyecto las unicas partes donde utilizas this.$gates es a la hora de configurarlo prnt.sc/JnKUPrV8l-h_ , y eso esta bien a mi me funciona, el problema como te mencione en este comentario es a la hora de utilizarlo en el script, en el template no tengo problema

Thread Thread
eduloper profile image
Genaro Hernández Author

Recién logro entenderte, no lo he utilizado como método como indica la documentación de Vue Gate, solo lo he utilizado como directiva. Pero recuerda que puedes aplicar un script de Composition Api y otro de Option Api en un mismo archivo vue 3.*; no he realizado las pruebas por falta de tiempo, pero quizá en la documentación oficial puedas encontrar una solución.

Thread Thread
eduloper profile image
Genaro Hernández Author
<script>
import { usePage } from '@inertiajs/inertia-vue3'
export default {
    created() {
        const roles = usePage().props.value.auth.roles;
        const permissions = usePage().props.value.auth.permisos;
        this.$gates.setRoles(roles);
        this.$gates.setPermissions(permissions);

        this.soyAdmin();
    },
    methods: {
        soyAdmin(){
            if(this.$gates.hasRole('admin')){
                console.log("soy admin");
            }else{
                console.log("no soy admin");
            }
        }
    }
}
</script>
Enter fullscreen mode Exit fullscreen mode
Collapse
jeffreynrock891 profile image
jeffreynrock891

hola amigo muy buen post pero tenia un par de dudas, si quiero agregar mas roles a un link como podria hacer ejempleto en este link que tienes aqui:

, quisiera que ingresara tambien otro rol, muchas gracias.
Collapse
eduloper profile image
Genaro Hernández Author

En la documentación de Vue Gates puedes encontrar mas alternativas de aplicación.

<button v-role:any="'writer|admin'">Add Article</button>
Enter fullscreen mode Exit fullscreen mode
Collapse
danilo2981 profile image
Dan Vega

Hola puedes poner el articulo sobre Laravel Permission por favor

Collapse
sancheznicolas profile image
Nicolas Delfor, Sanchez • Edited on

se puede adaptar para vue 2.5???

Collapse
eduloper profile image
Genaro Hernández Author

Según la documentación de Vue Gates e Inertia JS, son compatibles con Vue 2

Collapse
cacz18 profile image
Carlos Carrera

Hola Genaro, un agrado leer tu articulo, pero me he quedado con una duda, como integras vue-gates al proyecto? he tenido problemas con esa parte, puedes especificar un poco más?

Collapse
eduloper profile image
Genaro Hernández Author

Que tal Carlos, claro que si. Voy agregar ese detalle. Dame hasta mañana por favor que ando un poco atareado.

Collapse
needwit profile image
needwit

Y como consulto un permiso?