roles

package module
v0.0.0-...-dcaf8a4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 8, 2020 License: MIT Imports: 3 Imported by: 121

README

Roles

Roles is an authorization library for Golang, it also integrates nicely with QOR Admin.

GoDoc Build Status

Usage

Permission Modes

Permission modes are really the roles in Roles. Roles has 5 default permission modes:

  • roles.Read
  • roles.Update
  • roles.Create
  • roles.Delete
  • roles.CRUD // CRUD means Read, Update, Create, Delete

You can use those permission modes, or create your own by defining permissions.

Permission Behaviors and Interactions
  1. All roles in the Deny mapping for a permission mode are immediately denied without reference to the Allow mapping for that permission mode.

    E.g.

    roles.Deny(roles.Delete, roles.Anyone).Allow(roles.Delete, "admin")
    

    will deny access to admin for the permission mode roles.Delete, despite the chained call to Allow(). I.e. Allow() has NO effect in this chain.

  2. If there are NO roles in the Allow mapping for a permission mode, then roles.Anyone is allowed.

    E.g.

    roles.Deny(roles.CRUD, "customer")
    

    will allow access for permission mode roles.CRUD to any role that is not a customer because the Allow mapping is empty and the blanket allow rule is in force.

  3. If even one (1) Allow mapping exists, then only roles on that list will be allowed through.

    E.g.

    roles.Allow(roles.READ, "admin")
    

    allows the admin role through and rejects ALL other roles.

The following is a flow diagram for a specific permission mode, e.g. roles.READ.

st=>start: Input role
denied0=>end: Denied
allowed0=>end: Allowed
denied1=>end: Denied
allowed1=>end: Allowed
op0=>operation: Exists in Deny map?
op1=>operation: Allow map empty?
op2=>operation: Exists in Allow map?
cond0=>condition: Yes or No?
cond1=>condition: Yes or No?
cond2=>condition: Yes or No?

st->op0->cond0
cond0(no)->op1->cond1
cond0(yes)->denied0
cond1(yes)->allowed0
cond1(no)->op2->cond2
cond2(yes)->allowed1
cond2(no)->denied1

Please note that, when using Roles with L10n. The

// allows the admin role through and rejects ALL other roles.
roles.Allow(roles.READ, "admin")

might be invalid because L10n defined a permission system that applys new roles to the current user. For example, There is a user with role "manager", the EditableLocales in the L10n permission system returns true in current locale. Then this user actually has two roles "manager" and "locale_admin". because L10n set resource.Permission.Allow(roles.CRUD, "locale_admin") to the resource. So the user could access this resource by the role "locale_admin".

So you either use Deny instead which means swtich "white list" to "black list" or make the EditableLocales always return blank array which means disabled L10n permission system.

Define Permission
import "github.com/qor/roles"

func main() {
  // Allow Permission
  permission := roles.Allow(roles.Read, "admin") // `admin` has `Read` permission, `admin` is a role name

  // Deny Permission
  permission := roles.Deny(roles.Create, "user") // `user` has no `Create` permission

  // Using Chain
  permission := roles.Allow(roles.CRUD, "admin").Allow(roles.Read, "visitor") // `admin` has `CRUD` permissions, `visitor` only has `Read` permission
  permission := roles.Allow(roles.CRUD, "admin").Deny(roles.Update, "user") // `admin` has `CRUD` permissions, `user` doesn't has `Update` permission

  // roles `Anyone` means for anyone
  permission := roles.Deny(roles.Update, roles.Anyone) // no one has update permission
}
Check Permission
import "github.com/qor/roles"

func main() {
  permission := roles.Allow(roles.CRUD, "admin").Deny(roles.Create, "manager").Allow(roles.Read, "visitor")

  // check if role `admin` has the Read permission
  permission.HasPermission(roles.Read, "admin")     // => true

  // check if role `admin` has the Create permission
  permission.HasPermission(roles.Create, "admin")     // => true

  // check if role `user` has the Read permission
  permission.HasPermission(roles.Read, "user")     // => true

  // check if role `user` has the Create permission
  permission.HasPermission(roles.Create, "user")     // => false

  // check if role `visitor` has the Read permission
  permission.HasPermission(roles.Read, "user")     // => true

  // check if role `visitor` has the Create permission
  permission.HasPermission(roles.Create, "user")     // => false

  // Check with multiple roles
  // check if role `admin` or `user` has the Create permission
  permission.HasPermission(roles.Create, "admin", "user")     // => true
}
Register Roles

When checking permissions, you will need to know current user's roles first. This could quickly get out of hand if you have defined many roles based on lots of conditions - so Roles provides some helper methods to make it easier:

import "github.com/qor/roles"

func main() {
  // Register roles based on some conditions
  roles.Register("admin", func(req *http.Request, currentUser interface{}) bool {
      return req.RemoteAddr == "127.0.0.1" || (currentUser.(*User) != nil && currentUser.(*User).Role == "admin")
  })

  roles.Register("user", func(req *http.Request, currentUser interface{}) bool {
    return currentUser.(*User) != nil
  })

  roles.Register("visitor", func(req *http.Request, currentUser interface{}) bool {
    return currentUser.(*User) == nil
  })

  // Get roles from a user
  matchedRoles := roles.MatchedRoles(httpRequest, user) // []string{"user", "admin"}

  // Check if role `user` or `admin` has Read permission
  permission.HasPermission(roles.Read, matchedRoles...)
}

License

Released under the MIT License.

Documentation

Index

Constants

View Source
const (
	// Anyone is a role for any one
	Anyone = "*"
)

Variables

View Source
var ErrPermissionDenied = errors.New("permission denied")

ErrPermissionDenied no permission error

View Source
var Global = &Role{}

Global global role instance

Functions

func HasRole

func HasRole(req *http.Request, user interface{}, roles ...string) bool

HasRole check if current user has role

func MatchedRoles

func MatchedRoles(req *http.Request, user interface{}) []string

MatchedRoles return defined roles from user

func Register

func Register(name string, fc Checker)

Register register role with conditions

func Remove

func Remove(name string)

Remove role definition from global role instance

func Reset

func Reset()

Reset role definitions from global role instance

Types

type Checker

type Checker func(req *http.Request, user interface{}) bool

Checker check current request match this role or not

func Get

func Get(name string) (Checker, bool)

Get role defination

type Permission

type Permission struct {
	Role         *Role
	AllowedRoles map[PermissionMode][]string
	DeniedRoles  map[PermissionMode][]string
}

Permission a struct contains permission definitions

func Allow

func Allow(mode PermissionMode, roles ...string) *Permission

Allow allows permission mode for roles

func Deny

func Deny(mode PermissionMode, roles ...string) *Permission

Deny deny permission mode for roles

func NewPermission

func NewPermission() *Permission

NewPermission initialize a new permission for default role

func (*Permission) Allow

func (permission *Permission) Allow(mode PermissionMode, roles ...string) *Permission

Allow allows permission mode for roles

func (*Permission) Concat

func (permission *Permission) Concat(newPermission *Permission) *Permission

Concat concat two permissions into a new one

func (*Permission) Deny

func (permission *Permission) Deny(mode PermissionMode, roles ...string) *Permission

Deny deny permission mode for roles

func (Permission) HasPermission

func (permission Permission) HasPermission(mode PermissionMode, roles ...interface{}) bool

HasPermission check roles has permission for mode or not

type PermissionMode

type PermissionMode string

PermissionMode permission mode

const (
	// Create predefined permission mode, create permission
	Create PermissionMode = "create"
	// Read predefined permission mode, read permission
	Read PermissionMode = "read"
	// Update predefined permission mode, update permission
	Update PermissionMode = "update"
	// Delete predefined permission mode, deleted permission
	Delete PermissionMode = "delete"
	// CRUD predefined permission mode, create+read+update+delete permission
	CRUD PermissionMode = "crud"
)

type Permissioner

type Permissioner interface {
	HasPermission(mode PermissionMode, roles ...interface{}) bool
}

Permissioner permissioner interface

func ConcatPermissioner

func ConcatPermissioner(ps ...Permissioner) Permissioner

ConcatPermissioner concat permissioner

type Role

type Role struct {
	// contains filtered or unexported fields
}

Role is a struct contains all roles definitions

func New

func New() *Role

New initialize a new `Role`

func (*Role) Allow

func (role *Role) Allow(mode PermissionMode, roles ...string) *Permission

Allow allows permission mode for roles

func (*Role) Deny

func (role *Role) Deny(mode PermissionMode, roles ...string) *Permission

Deny deny permission mode for roles

func (*Role) Get

func (role *Role) Get(name string) (Checker, bool)

Get role defination

func (*Role) HasRole

func (role *Role) HasRole(req *http.Request, user interface{}, roles ...string) bool

HasRole check if current user has role

func (*Role) MatchedRoles

func (role *Role) MatchedRoles(req *http.Request, user interface{}) (roles []string)

MatchedRoles return defined roles from user

func (*Role) NewPermission

func (role *Role) NewPermission() *Permission

NewPermission initialize permission

func (*Role) Register

func (role *Role) Register(name string, fc Checker)

Register register role with conditions

func (*Role) Remove

func (role *Role) Remove(name string)

Remove role definition

func (*Role) Reset

func (role *Role) Reset()

Reset role definitions

type Roler

type Roler interface {
	GetRoles() []string
}

Roler Roler interface

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL