Skip to content

Instantly share code, notes, and snippets.

@maykbrito
Created August 12, 2019 10:08
Show Gist options
  • Star 12 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save maykbrito/ac8cdcc382fbc7012edd99e24c498f34 to your computer and use it in GitHub Desktop.
Save maykbrito/ac8cdcc382fbc7012edd99e24c498f34 to your computer and use it in GitHub Desktop.
Basic step-by-step to use ACL in AdonisJS

Install

adonis install adonis-acl

Config

app.js

providers

'adonis-acl/providers/AclProvider'

aceProviders

'adonis-acl/providers/CommandsProvider'

aliases

Role: 'Adonis/Acl/Role',
Permission: 'Adonis/Acl/Permission'

kernel.js

globalMiddleware

'Adonis/Acl/Init'

namedMiddleware

is: 'Adonis/Acl/Is',
can: 'Adonis/Acl/Can'

Models/User.js

static get traits() {
    return [
        '@provider:Adonis/Acl/HasRole',
        '@provider:Adonis/Acl/HasPermission'
    ]  
}

Migrations

adonis acl:setup
adonis migration:run

CRUD Permission

Controllers

adonis make:controller Permission
adonis make:controller Role

PermissionController.js

const Permission = use('Permission');

class PermissionController {

  index() {
    return Permission.all()  
  }

  async store({request}) {
      const data = request.only(['name', 'slug', 'description'])
      const permission = Permission.create(data)
      return permission
  }

  async update({ request, params }) {
    const data = request.only(['name', 'slug', 'description'])

    const permission = await Permission.findOrFail(params.id)

    permission.merge(data)

    await permission.save()

    return permission
  }


  async destroy({ params }) {
    const permission = await Permission.findOrFail(params.id)

    permission.delete()
  }

}

routes.js

Route.resource('permission', 'PermissionController').apiOnly().middleware('auth')

Insomnia

POST: base_url/permissions

{
  "name":"Create User",
  "slug":"create_user",
  "description":"Create a user"
}

CRUD Role

RoleController.js

const Role = use('Role')


class RoleController {


  async index() {
    const roles = await Role.query().with('permissions').fetch()

    return roles
  }

  async show({ params }){
    const role = await Role.findOrFail(params.id)

    await role.with('permissions')

    return role
  }

  async store({ request }) {
    const { permissions, ...data } = request.only(['name', 'slug', 'description', 'permission'])

    const role = await Role.create(data)

    if (permissions) {
      await role.permissions().attach(permissions)
    }

    await role.load('permissions')

    return role
  }

  async update({ request, params }) {
    const { permissions, ...data } = request.only(['name', 'slug', 'description', 'permission'])

    const role = await Role.findOrFail(params.id)

    role.merge(data)

    await role.save()

    if (permissions) {
      await role.permissions().sync(permissions)
    }

    await role.load('permissions')

    return role
  }

  async destroy({ params }) {
    const role = await Role.findOrFail(params.id)

    await role.delete()
  }
}

routes.js

Route.resource('/roles', RoleController).apiOnly().middleware('auth')

Insominia

POST: base_url/roles

{
  "name":"Administrator",
  "slug":"administrator",
  "description":"Admin of site"
}

PUT: base_url/roles

{
  "permission":[1,2,3]
}

Adjust UserController

UserController.js

store

  • get permissions and roles from request
  • check if(roles)
  • await for user.roles().attach(roles)
  • check if(permissions)
  • await user.permissions().attach(permissions)
  • await for user.loadMany(['roles', 'permissions'])

update

  • same for store but with sync instead of attach

Insomnia

PUT: base_url/users/1

{
  "roles":[1]
}

POST: base_url/users

{
  "email": "newadmin@email.com",
  "roles":[1]
}

{ 
  "email":"newnormaluser@email.com",
  "permissions":[2]
}

Using ACL with middleware

route.js

Route.resource('/posts', 'PostController')i
.apiOnly()
.execpt(['index', 'show'])
.middleware(['auth', 'is:(administrator || moderator)'])

Route.get('/posts', 'PostController')
.middleware(['auth', 'can:read_posts'])

Route.get('/posts/:id', 'PostController')
.middleware(['auth', 'can:(read_posts|| something)'])

Using ACL inline in Controller

async index({ request, auth }) {
  const user = await auth.getUser()

  if (await user.can('read_private_posts'))
    return Post.all()

  const posts = await Post.query()
  .where({ type: 'public'})
  .fetch()

  return posts
  
}

async show({params, auth, response}) {
  const post = await Post.findOrFail(params.id)

  if (post.type === "public") return post

  const user = await auth.getUser()

  if (await user.can("read_private_posts")) return post

  return response.status.(400).send({error:{message:"Permission denied"}})
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment