Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How do I share permissions with front-end? #227

Closed
kshitizshankar opened this issue Oct 9, 2019 · 6 comments
Closed

How do I share permissions with front-end? #227

kshitizshankar opened this issue Oct 9, 2019 · 6 comments
Labels

Comments

@kshitizshankar
Copy link

Hey - A bit new to CASL so still trying to understand a few things

I have a FeathersJS server with Vue + FeathersVuex frontend. Read all the articles regarding these but I am still not really sure about how it's supposed to work essentially.

In my scenario, I have

  1. Users
  2. Organizations - They have Admins, Members and Guests
  3. Projects - They have project admins, team members and guest.

Basic rules are -

  1. Authenticated users can create new organizations
  2. Organization admins can manage their organization
  3. Organization admins can invite new members
  4. Organization admins and members can create new projects
    and so on...

On the server, I created a set of abilities (am not sure if I did it right though)
I am using the code setup similar to https://blog.feathersjs.com/authorization-with-casl-in-feathersjs-app-fd6e24eefbff to define abilities.

Since I have a separate collection for permissions, I am querying that to build extra information that is being used to build the abilities.

For example -
Given a user, I am building out an object like -

organizations: {
    admin: ['orgId_1', 'orgId_2', 'orgId_3'],
    member: ['orgId_4']
},
projects: {
    projectadmin: ['p1','p2'],
    projectmember: ['p3']
}
...

Based on this object, I am defining the permissions using $in

// All users can create new organizations
can('create', ['organizations']);

// User can CRUD organizations if they are an admin of the organization.
can(['manage'], 'organizations', { _id: {$in: [ ...user.organizations.admin ] }})

//User can create a project if they are a member of the organization
can(['create', 'read'], 'projects, {orgId: {$in: [...user.organizations.admin, ......user.organizations.member]}})
...

The rest of the flow is the same as the article where the authorize hook calls to check if the current user has permission to perform the action on the service.

Questions -

  1. Is this the right way or am I doing something horribly wrong here?
  2. On the server, it works with toMongoQuery to add the right query params to the API calls - How do I share these permissions with the UI? I tried sending over these rules to the frontend upon successful login but now I am not sure how to actually use $can to validate access.

So for example - On the front-end, I get something like this -



    {
        "actions": [
            "create"
        ],
        "subject": [
            "organizations"
        ],
        "inverted": false,
        "conditions": null,
        "fields": null,
        "reason": null
    },
    {
        "actions": [
            "manage"
        ],
        "subject": [
            "organizations"
        ],
        "inverted": false,
        "conditions": {
            "_id": {
                "$in": [
                    "ORG_ID_1", "ORG_ID_2"
                ]
            }
        },
        "fields": null,
        "reason": null
    },

On the front-end, I tried referring to the Vue Plugin and article but it feels like I am missing something here.

@stalniy
Copy link
Owner

stalniy commented Oct 10, 2019

Hi,

On the first sight, everything looks correct.

On the UI side, you have separate ability instance. If you use Vuex better to create it separately (in order to share between vuex and Vue), then on login, in your vuex action update rules of that instance (ability.update(response.data.permissions), store that permissions the same way you store auth token, so they can be restored on page reload).

@stalniy
Copy link
Owner

stalniy commented Oct 10, 2019

Take a look at the vuex example: https://github.com/stalniy/casl-vue-api-example/blob/master/src/store/ability.js

It implements this as store plugin.

@kshitizshankar
Copy link
Author

Hey @stalniy

Thanks for the reply - (and sorry I missed the notification it seems).

On the first sight, everything looks correct.

Phew - Thats reassuring! I was quite sure I messed it up somehow.

On the UI side, you have separate ability instance. If you use Vuex better to create it separately (in order to share between vuex and Vue), then on login, in your vuex action update rules of that instance (ability.update(response.data.permissions), store that permissions the same way you store auth token, so they can be restored on page reload).

Yes, I have exactly that. I went through the vuex example already and have that working.

What I can't seem to figure out is how to test the abilities.

For example - 2 Users A and B. A can create new things inside a project, B can only read.
So, the permissions would be something like -

{
        "actions": [
            "create"
        ],
        "subject": [
            "things"
        ],
        "inverted": false,
        "conditions": {
            "projectID": {
                "$in": [
                    "PROJECT_ID_1", "PROJECT_ID_2"
                ]
            }
        },
        "fields": null,
        "reason": null
    },

How do I hide/show "create" button? Basically, what should I be passing to the $can function to test -
if the I can [create], [things], [in project with id = project_id_1]

I went through the documentation for testing abilities but not sure how to do this https://github.com/stalniy/casl/tree/master/packages/casl-vue

Also, I figured I could use toMongoQuery on the frontend as well to filter things in the Feathers-Vuex queries - not sure if that is the way to go about it or not.

Thanks a lot!

@stalniy
Copy link
Owner

stalniy commented Oct 15, 2019

You need to pass an instance of thing. Casl by default uses constructor name or modelName to detect the subject name.

For example,

<button v-if=“$can(“create”, thing)”>create</button>

Where thing is either an instance of Thing or regular object that has projectID field.

If you use POJO for the thing then you need casl to say how to determine its name. To do this you need to pass subjectName function in Ability constructor (you can find more info about this in “checking abilities” docs)

@stalniy
Copy link
Owner

stalniy commented Oct 21, 2019

@kshitizshankar does it make sense?

@stalniy
Copy link
Owner

stalniy commented Oct 28, 2019

Close as there is no action items from casl side.

Thanks for the interest in casl!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants