Role Based Access Control (RBAC) for your go application

This package allows you to manage user permissions and roles in your database.

👇 Setup

Install

go get github.com/Permify/permify-gorm

Run All Tests

go test ./...

Get the database driver for gorm that you will be using

# mysql 
go get gorm.io/driver/mysql 
# or postgres
go get gorm.io/driver/postgres
# or sqlite
go get gorm.io/driver/sqlite
# or sqlserver
go get gorm.io/driver/sqlserver
# or clickhouse
go get gorm.io/driver/clickhouse

Import permify.

import permify `github.com/Permify/permify-gorm`

Initialize the new Permify.

// initialize the database. (you can use all gorm's supported databases)
db, _ := gorm.Open(mysql.Open("user:[email protected](host:3306)/db?charset=utf8&parseTime=True&loc=Local"), &gorm.Config{})

// New initializer for Permify
// If migration is true, it generate all tables in the database if they don't exist.
permify, _ := permify.New(permify.Options{
	Migrate: true,
	DB: db,
})

🚲 Basic Usage

This package allows users to be associated with permissions and roles. Each role is associated with multiple permissions.

// CreateRole create new role.
// Name parameter is converted to guard name. example: senior $#% associate -> senior-associate.
// If a role with the same name has been created before, it will not create it again. (FirstOrCreate)
// First parameter is role name, second parameter is role description.
err := permify.CreateRole("admin", "role description")

// CreatePermission create new permission.
// Name parameter is converted to guard name. example: create $#% contact -> create-contact.
// If a permission with the same name has been created before, it will not create it again. (FirstOrCreate)
err := permify.CreatePermission("edit user details", "")

Permissions can be added to a role using AddPermissionsToRole method in different ways:

// first parameter is role id
err := permify.AddPermissionsToRole(1, "edit user details")
// or
err := permify.AddPermissionsToRole("admin", []string{"edit user details", "create contact"})
// or
err := permify.AddPermissionsToRole("admin", []uint{1, 3})

With using these methods you can remove and overwrite permissions:

// overwrites the permissions of the role according to the permission names or ids.
err := permify.ReplacePermissionsToRole("admin", []string{"edit user details", "create contact"})

// remove permissions from role according to the permission names or ids.
err := permify.RemovePermissionsFromRole("admin", []string{"edit user details"})

Basic fetch queries:

// Fetch all the roles. (with pagination option).
// If withPermissions is true, it will preload the permissions to the role.
// If pagination is nil, it returns without paging.
roles, totalCount, err := permify.GetAllRoles(options.RoleOption{
	WithPermissions: true,
	Pagination: &utils.Pagination{
		Page: 1,
		Limit: 1,
	},
})

// without paging.
roles, totalCount, err := permify.GetAllRoles(options.RoleOption{
    WithPermissions: false,
})

// The data returned is a collection of roles.
// Collections provides a fluent convenient wrapper for working with arrays of data.
fmt.Println(roles.IDs())
fmt.Println(roles.Names())
fmt.Println(roles.Permissions().Names())

// Fetch all permissions of the user that come with direct and roles.
permissions, _ := permify.GetAllPermissionsOfUser(1)

// Fetch all direct permissions of the user. (with pagination option)
permissions, totalCount, err := permify.GetDirectPermissionsOfUser(1, options.PermissionOption{
    Pagination: &utils.Pagination{
        Page: 1,
        Limit: 10,
    },
})

Controls

// does the role or any of the roles have given permission?
can, err := permify.RoleHasPermission("admin", "edit user details")

// does the role or roles have any of the given permissions?
can, err := permify.RoleHasAnyPermissions([]string{"admin", "manager"}, []string{"edit user details", "create contact"})

// does the role or roles have all the given permissions?
can, err := permify.RoleHasAllPermissions("admin", []string{"edit user details", "create contact"})

// does the user have the given permission? (including the permissions of the roles)
can, err := permify.UserHasPermission(1, "edit user details")

// does the user have the given permission? (not including the permissions of the roles)
can, err := permify.UserHasDirectPermission(1, "edit user details")

// does the user have any of the given permissions? (including the permissions of the roles)
can, err := permify.UserHasAnyPermissions(1, []uint{1, 2})

// does the user have all the given roles?
can, err := permify.UserHasAllRoles(1, []string{"admin", "manager"})

// does the user have any of the given roles?
can, err := permify.UserHasAnyRoles(1, []string{"admin", "manager"})

🚘 Using permissions via roles

Adding Role

Add roles to user according to the role names or ids:

// add one role to user
err := permify.AddRolesToUser(1, "admin")

// you can also add multiple roles at once
err := permify.AddRolesToUser(1, []string{"admin", "manager"})
// or
err := permify.AddRolesToUser(1, []uint{1,2})

Replace the roles of the user according to the role names or ids:

// remove all user roles and add admin role
err := permify.ReplaceRolesToUser(1, "admin")

// you can also replace multiple roles at once
err := permify.ReplaceRolesToUser(1, []string{"admin", "manager"})
// or
err := permify.RemoveRolesFromUser(1, []uint{1,2})

Remove the roles of the user according to the role names or ids:

// remove one role to user
err := permify.RemoveRolesFromUser(1, "admin")

// you can also remove multiple roles at once
err := permify.RemoveRolesFromUser(1, []string{"admin", "manager"})
// or
err := permify.RemoveRolesFromUser(1, []uint{1,2})

Control Roles

// does the user have the given role?
can, err := permify.UserHasRole(1, "admin")

// does the user have all the given roles?
can, err := permify.UserHasAllRoles(1, []string{"admin", "manager"})

// does the user have any of the given roles?
can, err := permify.UserHasAnyRoles(1, []string{"admin", "manager"})

Get User’s Roles

roles, totalCount, err := permify.GetRolesOfUser(1, options.RoleOption{
    WithPermissions: true, // preload role's permissions
    Pagination: &utils.Pagination{
        Page: 1,
        Limit: 1,
    },
})

// the data returned is a collection of roles. 
// Collections provides a fluent convenient wrapper for working with arrays of data.
fmt.Println(roles.IDs())
fmt.Println(roles.Names())
fmt.Println(roles.Len())
fmt.Println(roles.Permissions().Names())

Add Permissions to Roles

// add one permission to role
// first parameter can be role name or id, second parameter can be permission name(s) or id(s).
err := permify.AddPermissionsToRole("admin", "edit contact details")

// you can also add multiple permissions at once
err := permify.AddPermissionsToRole("admin", []string{"edit contact details", "delete user"})
// or
err := permify.AddPermissionsToRole("admin", []uint{1, 2})

Remove Permissions from Roles

// remove one permission to role
err := permify.RemovePermissionsFromRole("admin", "edit contact details")

// you can also add multiple permissions at once
err := permify.RemovePermissionsFromRole("admin", []string{"edit contact details", "delete user"})
// or
err := permify.RemovePermissionsFromRole("admin", []uint{1, 2})

Control Role’s Permissions

// does the role or any of the roles have given permission?
can, err := permify.RoleHasPermission([]string{"admin", "manager"}, "edit contact details")

// does the role or roles have all the given permissions?
can, err := permify.RoleHasAllPermissions("admin", []string{"edit contact details", "delete contact"})

// does the role or roles have any of the given permissions?
can, err := permify.RoleHasAnyPermissions(1, []string{"edit contact details", "delete contact"})

Get Role’s Permissions

permissions, totalCount, err := permify.GetPermissionsOfRoles([]string{"admin", "manager"}, options.PermissionOption{
    Pagination: &utils.Pagination{
        Page: 1,
        Limit: 1,
    },
})

// the data returned is a collection of permissions. 
// Collections provides a fluent convenient wrapper for working with arrays of data.
fmt.Println(permissions.IDs())
fmt.Println(permissions.Names())
fmt.Println(permissions.Len())

🚤 Direct Permissions

Adding Direct Permissions

Add direct permission or permissions to user according to the permission names or ids.

// add one permission to user
err := permify.AddPermissionsToUser(1, "edit contact details")

// you can also add multiple permissions at once
err := permify.AddPermissionsToUser(1, []string{"edit contact details", "create contact"})
// or
err := permify.AddPermissionsToUser(1, []uint{1,2})

Remove the roles of the user according to the role names or ids:

// remove one role to user
err := permify.RemovePermissionsFromUser(1, "edit contact details")

// you can also remove multiple permissions at once
err := permify.RemovePermissionsFromUser(1, []string{"edit contact details", "create contact"})
// or
err := permify.RemovePermissionsFromUser(1, []uint{1,2})

Control Permissions

// ALL PERMISSIONS

// does the user have the given permission? (including the permissions of the roles)
can, err := permify.UserHasPermission(1, "edit contact details")

// does the user have all the given permissions? (including the permissions of the roles)
can, err := permify.UserHasAllPermissions(1, []string{"edit contact details", "delete contact"})

// does the user have any of the given permissions? (including the permissions of the roles).
can, err := permify.UserHasAnyPermissions(1, []string{"edit contact details", "delete contact"})

// DIRECT PERMISSIONS

// does the user have the given permission? (not including the permissions of the roles)
can, err := permify.UserHasDirectPermission(1, "edit contact details")

// does the user have all the given permissions? (not including the permissions of the roles)
can, err := permify.UserHasAllDirectPermissions(1, []string{"edit contact details", "delete contact"})

// does the user have any of the given permissions? (not including the permissions of the roles)
can, err := permify.UserHasAnyDirectPermissions(1, []string{"edit contact details", "delete contact"})

Get User’s All Permissions

permissions, err := permify.GetAllPermissionsOfUser(1)

// the data returned is a collection of permissions. 
// Collections provides a fluent convenient wrapper for working with arrays of data.
fmt.Println(permissions.IDs())
fmt.Println(permissions.Names())
fmt.Println(permissions.Len())

Get User’s Direct Permissions

permissions, totalCount, err := permify.GetDirectPermissionsOfUser(1, options.PermissionOption{
    Pagination: &utils.Pagination{
        Page:  1,
        Limit: 10,
    },
})

// the data returned is a collection of permissions.
// Collections provides a fluent convenient wrapper for working with arrays of data.
fmt.Println(permissions.IDs())
fmt.Println(permissions.Names())
fmt.Println(permissions.Len())

🚀 Using your user model

You can create the relationships between the user and the role and permissions in this manner. In this way:

  • You can manage user preloads
  • You can create foreign key between users and pivot tables (user_roles, user_permissions).

import (
    "gorm.io/gorm"
    models `github.com/Permify/permify-gorm/models`
)

type User struct {
    gorm.Model
    Name string

    // permify
    Roles       []models.Role       `gorm:"many2many:user_roles;constraint:OnUpdate:CASCADE,OnDelete:CASCADE"`
    Permissions []models.Permission `gorm:"many2many:user_permissions;constraint:OnUpdate:CASCADE,OnDelete:CASCADE"`
}

⁉️ Error Handling

ErrRecordNotFound

You can use error handling in the same way as gorm. for example:

// check if returns RecordNotFound error
permission, err := permify.GetPermission(1)
if errors.Is(err, gorm.ErrRecordNotFound) {
	// record not found
}

Errors

Errors List

Need More, Check Out our API

Permify API is an authorization API which you can add complex rbac and abac solutions.

❤️ Let’s get connected:


guilyx | Twitter


guilyx's LinkdeIN

GitHub

View Github