Git Product home page Git Product logo

williamcruzme / vue-gates Goto Github PK

View Code? Open in Web Editor NEW
262.0 8.0 30.0 308 KB

πŸ”’ A Vue.js & Nuxt.js plugin that allows you to use roles and permissions in your components or DOM elements, also compatible as middleware and methods.

Home Page: https://williamcruzme.github.io/vue-gates/

License: MIT License

JavaScript 100.00%
laravel permissions roles gates nuxt role directives vuejs vue2 vue3 vuex ssr middleware

vue-gates's Introduction

Vue Gates - Protecting every thing

Version Vue Vue Downloads License

vue-gates is a plugin for Vue.js & Nuxt.js that allows you to use roles and permissions in your components or DOM elements, also compatible as middleware and methods.

See the full documentation

Features

  • Persistent roles/permissions
  • Super role avoids all role and permission validations
  • Directives
  • Middlewares
  • Methods
  • Wildcard support
  • Support server-side rendering (Nuxt.js)
  • TypeScript support
  • Compatible with IE11

βœ… Examples

See the examples and instructions with Laravel.

🚸 Contributing

You are welcome to contribute to this project, but before you do, please make sure you read the contribution guide.

πŸ™ˆ Credits

  • Inspired by Laravel Permission syntax.

πŸ”’ License

MIT

vue-gates's People

Contributors

cesaramirez avatar daviddriessen avatar dependabot[bot] avatar gaetandezeiraud avatar williamcruzme avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

vue-gates's Issues

Wildcards not supported

I assume this is not compatible with permission wildcards, as I can't get it to work

using: {{ this.$laravel.getPermissions() }} results in [ "*.view", "*.create" ] but v-can="'users.create'" doesn't trigger

Ref: Spatie wildcard permissions docs

Could you please add support for wildcards ?

Nuxt: getting empty permission on first reload

Hello,

Thank you for this great package, when I log in the the user and redirect it to my dashboard all permissions are loaded well. but if the user reload the page it does not work properly, I have :

// layouts/default.vue

async mounted() {
  const [roles, permissions] = await Promise.all([
    this.$axios.$get('/api/admin/user/roles'),
    this.$axios.$get('/api/admin/user/permissions'),
  ])

  this.$gates.setRoles(roles.data)
  this.$gates.setPermissions(permissions.data)
},
// components/layouts/menu.vue

<NuxtLink v-can="'dashboard.index'" class="sidebar-link" to="/dashboard"> Dashboard </NuxtLink> // it does not show

Vue 3 support?

Currently, I have the following error Uncaught TypeError: Cannot set property '$gates' of undefined.
At :

var index = {
    install: function install(Vue) {
      var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
      var gate = new Gate(options);
      Vue.prototype.$gates = gate; // here
      Vue.gates = gate;
      registerDirectives(Vue);
    }
  };

this.$gates is not defined in Vue3 with Pinia installed

Hello,

I'm trying to access this.$gates.setRoles([...roles]) inside my pinia store, but I'm getting the error TypeError: Cannot read properties of undefined (reading 'setRoles')

import {defineStore} from "pinia";
import axios from 'axios';

export const useUserStore = defineStore("UserStore", {
    state: () => {
        return {
            user: [],
            authenticated: false,
        }
    },
    actions: {
        async fill() {
            try {
                const res = await axios.get('v1/user');
                if (res) {
                    this.user = res.data
                    this.authenticated = true
                    try {
                        this.$gates.setRoles(res.data.roles)
                    } catch (e) {
                        console.log(e)
                    }
                }
            } catch (err) {
                this.user = []
                this.authenticated = false
            }
        }
    }
});

I've also tried with Vue.prototype.$gates, but that does not work either.
I've tried to import VueGates at the top, but that did not work either.

Documentation is really bare and should be improved.

How about a super user?

Like Laravel; we can grant access to all permissions for user by set Gate::before() method.

How can we implement it on the front end side? maybe setting a super role during registering the component like:

Vue.use(LaravelPermissions, { persistent: true, superRole: 'admin' });

so that meens if the auth user has role 'admin' he could pass all permissions.

I'm willing to implement this in a PR but give me a little guidance please. Thanks.

TypeScript declaration is wrong

Problem

The VueGates declaration is defined like this:

declare class VueGates {
  install: (app: any, options?: VueGatesOptions) => void
}

This won't work and gives a compile error:

No overload matches this call.
  Overload 1 of 2, '(plugin: PluginObject<unknown> | PluginFunction<unknown>, options?: unknown): VueConstructor<Vue>', gave the following error.
    Argument of type 'typeof VueGates' is not assignable to parameter of type 'PluginObject<unknown> | PluginFunction<unknown>'.
      Property 'install' is missing in type 'typeof VueGates' but required in type 'PluginObject<unknown>'.
  Overload 2 of 2, '(plugin: PluginObject<any> | PluginFunction<any>, ...options: any[]): VueConstructor<Vue>', gave the following error.
    Argument of type 'typeof VueGates' is not assignable to parameter of type 'PluginObject<any> | PluginFunction<any>'.
      Property 'install' is missing in type 'typeof VueGates' but required in type 'PluginObject<any>'.

Reason

The class is used as typeOf parameter when register the plugin like this:

import Vue from 'vue'
import { Plugin } from '@nuxt/types'
import VueGates from 'vue-gates'

Vue.use(VueGates) // <-- Compile error

const gatesPlugin: Plugin = (_context, inject) => {
  inject('gates', Vue.prototype.$gates)
}

export default gatesPlugin

Fix

The install method declared must be static:

declare class VueGates {
  static install: (app: any, options?: VueGatesOptions) => void
}

This is how other Vue plugins with TypeScript support declare the types.

I would also suggest to use a proper parameter type for app like this:

import Vue as _Vue from 'vue'

declare class VueGates {
  static install: (app: _Vue, options?: VueGatesOptions) => void
}

VM173:1 Uncaught SyntaxError: Unexpected token u in JSON at position 0

ISSUE 1

VM173:1 Uncaught SyntaxError: Unexpected token u in JSON at position 0
when use

import Vue from 'vue';
import LaravelPermissions from 'laravel-permissions';

Vue.use(LaravelPermissions, {
  persistent: true
});

ISSUE 2

> TypeError: Cannot read property 'includes' of undefined
>     at Object.hasPermission (vendors.app.js:18752)

Using on NuxtJS.

role or permission not working in vuetify

role or permission not working in vuetify

<template v-slot:activator="{ on, attrs }"> <v-btn color="primary" dark class="mb-2" v-bind="attrs" v-on="on" v-permission="'add users'" > New Item </v-btn> </template>
if I write in out template like this working fine

<v-btn color="primary" dark class="mb-2" v-bind="attrs" v-on="on" v-permission="'add users'" > New Item </v-btn>

Question ! Using with Nuxt

@williamcruzme thanks for super cool lib. I wonder where should I put

const { data: permissions } = await axios.get('/api/permissions');
const { data: roles } = await axios.get('/api/roles');

this.$laravel.setPermissions(permissions);
this.$laravel.setRoles(roles);

while working with Nuxt?

Thanks in advance.

Alias not supporting arguments

<!-- Alias -->
<button v-can="'add articles'">Add Article</button>
Check for any permission in a list:
<button v-permission:any="'add articles|edit articles'">Configure</button>

you can't actually use v-can:any but would be really nice

permissions gets updated after page refresh.

Hello, thank you for this awesome plugin.

I am using NUXT js and my problem is....the permissions does not apply automatically until I refresh the page manually.

in login section

async userLogin() {
      try {
        let response = await this.$auth
          .loginWith('laravelSanctum', {
            data: this.login,
          })
          .then((res) => {
            console.log('asdfsf')
            this.$axios
              .get('/admin/permissions')
              .then((res) => this.$gates.setPermissions(res.data))
              // .then((res) => this.$forceUpdate())
              .catch((err) => console.log(err))
          })
      } catch (err) {
        console.log(err)

        if ((err.response.status = 401)) {
          this.getmessage(err.response.data.message)
        } else {
          this.getmessage('Something went wrong')
        }
      }
    },

#in sidebar
v-show="$gates.hasPermission('' + item.permission + '')"

after login, I am redirecting to the dashboard page. but there every permission returns false. 

now, if I refresh the page manually, then the permission system works. 

how to resolve this issue ? 

#after login
image

#after refresh
image

Live update roles

First of all, great package!
Very easy to use and is flexible and not overloaded.

One simple question:

Is there a way to update the roles / permissions and make use of the vue reactivity?

At the moment I am using this.$forceUpdate() after updating my permissions but this seams not the correct way.

Thank you.
Cheers

Using persistent causes an error

Hi John, thanks for developing this package.

I upgraded recently and started getting the following error:

Uncaught SyntaxError: Unexpected token u in JSON at position 0
    at JSON.parse (<anonymous>)
    at new Gate (vue-gates.js?e1b1:221)
    at Object.install (vue-gates.js?e1b1:323)
    at Function.Vue.use (vue.runtime.esm.js?2b0e:5107)
    at eval (vue-gates.js?511d:4)
    at Module../plugins/vue-gates.js (app.js:951)

Checking the source code, I saw that the constructor is trying to parse localStorage.getItem('roles') but this returns undefined, hence the error.

I'm using Nuxt, latest version. And I set the roles and permissions inside a Nuxt Auth plugin.

Is this an expected behaviour or am I doing something wrong? If not, I can PR a quick fix for this.

Vue3 Working Example

Hey there John,

May us beginners please have a working example for Vue3?

Thank you :-)

You must specify a value in the directive

im using the package as the docs says but i have a problem ... when i add the directive to my menu with vuetify i've a custom menu drawer file with a json to add my menu dinamycally like this

{ text: "PlaneaciΓ³n Estrategica", path: "/goals", allowedRoles: "root|rector|directivo", icon: { type: "feather", name: "check-square", stroke: "white", fill: "none" } },

i use this menu like this

<v-list-item v-else :key="item.text" link :to="item.path" v-role:any="item.allowedRoles" >

when i add :v-role:any="item.allowedRoles" it doesnt work but when i remove the : from :v-role it works with this error You must specify a value in the directive

Prevent a nested component from being loaded

Sorry for a rookie question.

How can I prevent a component from being loaded?

<div v-permission="'list-tasks'">
   <Tasks />
</div>

Although I check if user has "list-tasks" permission, Tasks component still loaded.

Note: I'm using Nuxt

Thank you in advance!

dumb question.. using $gates in store? - $gates is undefined

I've probably just had my brain go to sleep but when trying to use
this.$gates.setRoles() in the store (I've fetched user data inc roles and perms and want to load them) I also tried $gates.setRoles() with the same result

I get Uncaught (in promise) TypeError: this.$gates is undefined

I'm new to Vue in general so I've probably done something wrong :)

I do have it in my main.js

import { createApp } from 'vue'
import App from './App.vue'
import { store } from './store/index.js'
import { router }  from './routes/index.js'
import VueGates from 'vue-gates';

const app = createApp(App)
app.use(store)
app.use(router)
app.use(VueGates)
app.mount('#app')

Cannot read properties of null (reading 'includes') Error - After login in NuxtJs

Hello

I am using NuxtJs and keeps getting this weird error I tried moving in many places my code but it doesn't seem to work I'm using the persistent option to true

Everytime first time login I get this error
image

after refreshing the page it works as it should but everytime first time logging in it gives this error

I'm using the below code in default.vue layout folder

if (this.$store.state.auth.user.companies_usernames.includes('company')) {
      this.$gates.setRoles(['superuser'])
      this.$gates.setPermissions(['all'])
    } else {
      this.$store
        .dispatch(
          'user/getCurrentUser',
          this.$store.state.auth.user.company_username
        )
        .then(() => {
          this.$gates.setRoles([this.$store.state.user.currentUser.role])
          this.$gates.setPermissions(
            this.$store.state.user.currentUser.permissions
          )
        })
    }

Mounted user roles when logged in

Hello, @williamcruzme, is there a way to mounted Roles and Permission when logged In??

created() {
	async() => {
		const { data: permissions } = await this.$axios.get("/api/auth/permissions");
		const { data: roles } = await this.$axios.get("/api/auth/roles");

		this.$laravel.setPermissions(permissions);
		this.$laravel.setRoles(roles);
		console.log(permissions)
	}
}

I tried above code, but nothing happend in console.log

Thanks..

As Middleware?

Great stuff you got here!

A question though, I'm trying to make a middleware on Nuxt.js that is role-based. It is basically easier to have like,

 export default {
    name: 'dashboard',
    middleware: ['auth', 'role-admin']
  }

rather than checking each and every component of what role the user has

mounted(){
  if(this.$laravel.hasRole('admin') {
    // redirect
  }
}

So far, I've created a role-admin.js middeware with

export default function(context) {
  if (!process.server) {
    if( context.app.$laravel.hasRole('admin') {
       // redirect to their default page
    }
  }
}

But the thing is, context.app.$laravel is undefined.

Am I missing something? Thanks for your help!

TypeError: Cannot read properties of undefined (reading 'setPermissions') in Nuxt.js

` const role = this.$store.state.role.roles
const user = ['user']

        const roleJson = JSON.stringify(role)
        const userJson = JSON.stringify(user)
        if (roleJson === userJson) {
            this.$gates.setPermissions([
                'view sales',
                'add sales',
                'edit sales',
                'delete sales',
                'import sales',
                'summary report',
                'product report',
                'daily sale report',
                'monthly sale report',
                'daily purchase report',
                'sale report',
                'purchase report',
                'warehouse report',
                'product qty alert',
                'customer report',
                'supplier report',
                'due report',
                'pos'
            ])
            console.log(this.$gates)
        }`

<button v-permission="'add sales'">Add Sales</button>

setting in plugins/vue-gates.js
`import Vue from 'vue'
import VueGates from 'vue-gates'

Vue.use(VueGates)

export default (_context, inject) => {
inject('gates', Vue.prototype.$gates)
}`

someone please help me

.

Hello @williamcruzme

I don't know why when i set persistent to true in nuxt js an errors appears like this 'Error _classPrivateFieldGet(...) is null', is there any solution to solve this problem?

Just asking for clarification and suggestion

Hello @williamcruzme

Solution
Set the permissions/roles when you log in (before redirect), and enable persistent feature:

Vue.use(LaravelPermissions, { persistent: true });

Recommend solution
Work with Nuxt.js, you set the permissions/roles on the server side.

Originally posted by @williamcruzme in #15 (comment)

@williamcruzme How can the Recommend solution be implemented. I am having the same situation as mentioned in the issue. Although setting persistence to true seems to solve the problem, do you think it is the best idea to store user permissions in localStorage. Also, I noticed that the localStorage is not cleared when the user logs out.

Directives as functions in Vue 3

Hi, I am trying to use the directives as functions in Vue 3, but as Vue 3 with Composition API does not have access to this.$gates then I can't find a way to make it work.

In their documentation there are examples of this, but it doesn't work in vue 3 as usual.

this.$gates.hasRole('admin'); // false
this.$gates.unlessRole('admin'); // true
this.$gates.hasAnyRole('admin|writer'); // true
this.$gates.hasAllRoles('admin|writer'); // false

I have also tried with

import { getCurrentInstance } from "vue";

const app = getCurrentInstance();
app.$gates.hasRole('admin');

But it doesn't work for me.

I am using Laravel Inertia and I implement it as follows

// resources/js/Plugins/Permissions.js
import { usePage } from '@inertiajs/inertia-vue3'

export default {
    install: (app) => {
        app.mixin({
            mounted() {
                let user = usePage().props.value.auth.user
                if (user) {
                    let authRoles = user.roleNames;
                    let authPermissions = user.permissionNames;
                    this.$gates.setRoles(authRoles);
                    this.$gates.setPermissions(authPermissions);
                }
            }
        })
    }
}
// resources/js/app.js
require('./bootstrap');

import { createApp, h } from 'vue';
import { createInertiaApp } from '@inertiajs/inertia-vue3';
import { InertiaProgress } from '@inertiajs/progress';
import VueGates from 'vue-gates';
import Permissions from './Plugins/Permissions';
import store from './Plugins/Store';

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 package here
            .use(Permissions) // and here my implementation
            .use(store)
            .mixin({ methods: { route } })
            .mount(el);
    },
});

InertiaProgress.init({ color: '#4B5563' });

Everything works fine in the template directives, like v-role but I would like to be able to use it as functions as well.
Any ideas?

It is not possible to differentiate between the permissions that contain "-"

If we have two permissions that partially contains same string but they totally different permissions the package cant differentiate between them, For example: we have :
v-permission="'admin.dashboard.overview.ranking-data.no-of-visits'"
and
v-permission="'admin.dashboard.overview.ranking-data.no-of-visits-per-customer'"

These two permissions sounds the same to the Vue-Gates.

Feature requested - Directive like v-if

Hi, it's an awesome package, congratz.
Can you implemented a way to use directive like v-role in the same way of vue v-if.
Let me explain, the v-if don't render the element in DOM if the condition is false.
The directive implemented now like v-role or similar, renderer the element and process the condition for removing that.

Any ideas for making this goal?

EDIT:

Searching on SO i've found this hack for reaching the goal:

/**
 * Create comment node
 *
 * @private
 * @author https://stackoverflow.com/questions/43003976/a-custom-directive-similar-to-v-if-in-vuejs#43543814
 */
function commentNode(el, vnode) {
  const comment = document.createComment(' ')

  Object.defineProperty(comment, 'setAttribute', {
    value: () => undefined
  })

  vnode.text = ' '
  vnode.elm = comment
  vnode.isComment = true
  vnode.context = undefined
  vnode.tag = undefined
  vnode.data.directives = undefined

  if (vnode.componentInstance) {
    vnode.componentInstance.$el = comment
  }

  if (el.parentNode) {
    el.parentNode.replaceChild(comment, el)
  }
}

Thanks

Changing Permissions removes Parent and Children from DOM in wrong order (using bootstrap)

When changing the permissions in a running application (e.g. by calling a backend for updated permission) and updating them through setPermissions, many components rendering child components get removed from outward to inward. This leads to an error, where children try to remove themselve from a non existing parent.
This happens with multiple bootstrap components.
Attached you can find the errors and a code example.

Errors
image
image

Code
image

Temporary Fix:
You can fix this by using a v-show instead of the provided v-permission, which does not remove the element from the DOM but just hides it. As this can come with unwanted security implications its not an ideal fix.
image

Do you have any suggestion, how to fix this?

Unrecognized Vue directive

In my PHPStorm when I try to commit my changes it gives me a warning error: "Unrecognized Vue directive".
I have used v-role="" but it seems it's not registered globally.
Maybe it's an idea to do this?

superRole not working

I have added the superRole setting, something strange happens with the v-permission directive it works, but with the $ gates.hasPermission() method it does not recognize the superRole.

superRole implmentation questions

Hello,

Great library and seems easy but the documentation a bit lacking on explaining the setup of the superRole

If I made

import Vue from 'vue';
import VueGates from 'vue-gates';

Vue.use(VueGates, {
  superRole:true
});

then how would the library differentiate which role is what

or I can just use it as v-role="superRole" or v-permission="superRole"

this is a bit confusing to me on how to establish the flow of the superRole

would appreciate if you can help by explaining how would u implement it

thanks

Bug to check similar permissions

When I have a permission "security.create.role" and I check with the directive v-can or v-permission with the name "security.create.roles" or "security.create.roless", it is validated by true, when it should be false, since such permission does not exist.

Where is need to set roles and permissions?

I try to set it in store, but this.$laravel is not exists there. Where i need to do it
this.$laravel.setPermissions(this.$store.state.permissions); this.$laravel.setRoles(this.$store.state.roles);

I can set it in some component when 'mounted' or 'created' triggered, but it is no sense, cause it is already rendered.

Could someone help me, please?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.