npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@quantumlabs/adonisjs-cerberus

v2.0.2

Published

Adonis roles and permissions provider

Downloads

2

Readme

A Hellhound that protects your API Endpoints... 😈

npm version

Cerberus is a library that adds roles, resources and permissions to Auth System from Adonis Framework.

Table of Contents

Concept

Cerberus is a collection of models, commands, migrations and a middleware to help you managing User Access Rights in an Adonis.js API.

Warning: Cerberus doesn't yet manage Controllers and Routes for you. You'll need to create your custom methods using Cerberus Models.

To start using Cerberus properly, you need to understand some basic concepts behind the library. There are 3 main pillars (A.K.A Cerberus Heads), they are:

  1. Roles
  2. Resources
  3. Permissions

A Role is an User responsabilty in your API (e.g., Admin, Moderator, User, Seller, etc.).

A Resource can be a Controller, Model or any resource in your API that you want to protect (e.g., User, Profile, Post, etc.).

And we have Permissions. A Permission is basically the junction of Role and a Resource, with boolean values for each access right that a Role should give to a specific user_id. With Permissions we also have DefaultPermissions, they are Role-specific default values for Permissions boolean accesses. Every new Permission, should inherit from DefaultPermission rights, but they can assume whatever value you want.

The accesses are:

  1. Create
  2. Read
  3. Update
  4. Delete

Then, you can create Roles with DefaultPermissions and give Permissions to specific Resources and Users.

E.g.: You can create an "Admin" Role with a DefaultPermission to "Posts" Resource, and using the Permission model you can create a specific Permission to your User.

Role

{
  "id": 1,
  "name": "Admin",
  "slug": "admin"
}

Resource

{
  "id": 4,
  "name": "Posts",
  "slug": "posts"
}

DefaultPermission

{
  "id": 1,
  "resourceId": 4,
  "roleId": 1,
  "create": true,
  "read": true,
  "update": true,
  "delete" : true
}

Permission

{
  "id": 1,
  "resourceId": 4,
  "roleId": 1,
  "userId": 1,
  "create": true,
  "read": true,
  "update": true,
  "delete" : true
}

The Guard middleware will check values against Permission record, not DefaultPermission values.

Tables diagram

Setup

Install package using npm.

  adonis install @quantumlabs/adonisjs-cerberus

or

  npm i @quantumlabs/adonisjs-cerberus --save

Warning: If you choose npm install instead of adonis install, you'll need to open instructions.md manually.

Instructions

  1. Add Cerberus into providers Array, inside start/app.js file of your project:
  const providers = [
    ...
    '@quantumlabs/adonisjs-cerberus/providers/CerberusProvider',
    ...
  ]
  1. Add Cerberus into aceProviders Array, inside start/app.js file of your project:
  const aceProviders = [
    ...
    '@quantumlabs/adonisjs-cerberus/providers/CommandsProvider'
    ...
  ]
  1. Add Cerberus Middleware into namedMiddleware Array, inside start/kernel.js file of your project:
  const namedMiddleware = [
    ...
    guard: 'Cerberus/Middleware/Guard'
    ...
  ]
  1. Add Cerberus special Traits inside your app/Models/User Model, like this:
class User extends Model {
  static boot () {
    super.boot()

    this.addTrait('@provider:Cerberus/Traits/Role')
    this.addTrait('@provider:Cerberus/Traits/Permission')
  }
...
  1. If you're using Objection.js's Snake case to camel conversion, you should add this property at the end of your project config/database.js file:
  ...
  usingSnakeCaseMappers: true
}
  1. Finally, you need to run:
  adonis cerberus:init

This command will copy all library specific migrations into your project migrations folder.

Warning: Cerberus creates a migration for users table, adding a role_id column, which is a foreing key from roles. You should take a look in the migration before running it in production!

Commands

Init

  adonis cerberus:init

As mentioned before, this command should (and we hope it will) copy all library specific migration into your projects migrations folder. There's no special flags or parameters for this command.

Role

adonis cerberus:role [name] [slug]

Usage:
  cerberus:role <name> [slug] [options]

Arguments:
  name   Name of the role
  slug   Short name for role

This command creates a new role into roles table. You only need to specify role's name, slug argument is optional.

Resource

adonis cerberus:resource [name] [slug] [options]

Arguments:
  name               Name of the resource
  slug               Short name for resource

Options:
  -p, --defaultPermission   Generate default permissions
  -a, --always-ask   Ask which rights give in each Resource once (false by default)
  --from-models      Generate a resource for each app Model
  --from-controllers Generate a resource for each app Controller

This command creates a new resource into resources table. You only need to specify the name of resource, the slug argument is optional. The options are: -p, --defaultPermission - Generate default permissions -a, --always-ask - Ask which rights give in each Resource once (false by default) --from-models - Generate a resource for each app Model --from-controllers - Generate a resource for each app Controller

Default Permission

cerberus:defaultPermission [options]

Options:
  -a, --all               Run default permission creation for each Resource in database
  --resource-name <value> Name of resource

This command creates a new default permission into default_permissions table. You need to specify a Resource name, then, Cerberus creates a default permission record with the specified Resource name.

Usage

Using in routes

After creating your Permissions, you'll be able to start using Guard middleware in your routes.

It's simple to bind a permission into a route, look:

/**
* Get all users
* GET users
*/
Route
  .get('', 'UserController.index')
  .middleware(['auth', 'guard: user.read'])

You can also use multiple permissions in your route:

/**
* Create a new user
* POST users/register
*/
Route
  .post('register', 'UserController.register')
  .middleware(['auth', 'guard: user.create, user.read'])

And it's possible to use multiple resources too:

/**
* Fetch all posts with user profile
* GET posts
*/
Route
  .get('', 'PostController.index')
  .middleware(['auth', 'guard: post.read, user.read'])

Warning: You need to add the default auth middleware before Cerberus guard!

Consuming Models

You should use Cerberus Models to create Roles, Resources and Permissions in your own code. It's also useful for creating seeds or a complete CRUD to manage your Cerberus stuff. It's simple to use:

Roles

  const Role = use('Cerberus/Models/Role')

  // Creating a new Role
  await Role.create({
    name: 'Jedi Master',
    slug: 'jedi'
  })

  // or

  let role = await Role.find(1)

  role.name = 'Wookie'
  role.slug = 'wookie'

  await role.save()

  // You can use any Lucid methods you want

Resources

  const Resource = use('Cerberus/Models/Resource')

  // Creating a new Resource
  await Resource.create({
    name: 'Lightsaber',
    slug: 'lightsaber'
  })

  // or

  let resource = await Resource.find(1)

  resource.name = 'Force'
  resource.slug = 'force'

  await resource.save()

  // You can use any Lucid methods you want

DefaultPermissions

  const DefaultPermission = use('Cerberus/Models/DefaultPermission')

  // Creating a new DefaultPermission
  await Permission.create({
    role_id: role.id,
    resource_id: resource.id,
    create: false,
    read: true,
    update: false,
    delete: false
  })

  // or

  let defaultPermission = await DefaultPermission.find(1)

  defaultPermission.create = true
  defaultPermission.update = true

  await defaultPermission.save()

  // You can use any Lucid methods you want

Permissions

  const Permission = use('Cerberus/Models/Permission')

  // Creating a new Permission
  await Permission.create({
    role_id: role.id,
    user_id: user.id,
    resource_id: resource.id,
    create: false,
    read: true,
    update: false,
    delete: false
  })

  // or

  let permission = await Permission.find(1)

  permission.create = true
  permission.update = true

  await permission.save()

  // You can use any Lucid methods you want

Binding User to Role

You can simply bind an existing User to a Role:

  const User = use('App/Models/User')
  
  // Fetches the current user
  let user = await User.find(1)

  // Set the role Id
  user.role_id = 1

  await user.save()

Inheriting rights from DefaultPermissions

You can inherit rights from DefaultPermissions to Permission:

  const DefaultPermission = use('Cerberus/Models/DefaultPermission')
  const Permission = use('App/Models/Permission')
  const User = use('App/Models/User')
  
  // Fetches the current user
  let user = await User.find(1)

  // Get the default permission
  let defaultPermission = await DefaultPermission
      .query()
      .where('resourceId', resource.id)
      .orderBy('createdAt', 'desc')
      .limit(1)
      .fetch()

  defaultPermission = defaultPermission.first()

  if (defaultPermission) {
    // Create the default permission
    await Permission.create({
        roleId,
        user_id: user.id,
        resourceId: resource.id,
        create: defaultPermission.create,
        read: defaultPermission.read,
        update: defaultPermission.update,
        delete: defaultPermission.delete
      })
  }

Errors

By default, Cerberus throw 2 types of errors:

  1. CERBERUS_ACCESS_DENIED: This error occours when an User doesn't have the needed permissions for the specified Resource. The error status code is 403.
  2. CERBERUS_RESOURCE_NOT_FOUND: This error occours when you're trying to check for permissions in a Resource that doesn't exist. The error status code is 404.

You can handle this errors manually for custom messages. Check Adonis Framework Official Docs and search for Error Handling.

Tips

SQLite - If you're using SQLite, you may notice a bug when running user migrations. This happens because SQLite doesn't support ALTER TABLE with a constraint. Here you can find info about this issue in SQLite's official docs. I suggest you to create role_id foreign key manually in your user migration.

Todo

  • [x] Add an option in adonis cerberus:permission to run permission for every resource in database
  • [ ] Option to create custom permission rights
  • [ ] Methods for easy permission, role and resource binding
  • [ ] Setting a test utility and write tests for the existing code

Credits

Logo icon made by freepik from flaticon.com. Customized by QuantumLabs.