Skip to content

seancheung/privileges

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

17 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Privileges

Privilege and Group control for Laravel

Installation

You can install this package via composer using this command:

composer require panoscape/privileges

Register service provider:

config/app.php

'providers' => [
    ...
    Panoscape\Privileges\PrivilegesServiceProvider::class,
];

If you need blade directives, also add this:

config/app.php

'providers' => [
    ...
    Panoscape\Privileges\PrivilegesBladeServiceProvider::class,
];

A middleware can also be registered:

app/Http/Kernel.php

protected $routeMiddleware = [
  ...
  'privileges' => \Panoscape\Privileges\Middleware\PrivilegesMiddleware::class,
];

Publish profile config:

php artisan vendor:publish --provider="Panoscape\Privileges\PrivilegesServiceProvider" --tag="profile"

Modify the published profile template to suit your application.

config/privileges_profile.php

<?php

return [

    /*
    |--------------------------------------------------------------
    | User entity
    |--------------------------------------------------------------
    |
    */
    'user' => [

        /*
        |--------------------------------------------------------------
        | Model class
        |--------------------------------------------------------------
        |
        */
        'model' => '\App\User',

        /*
        |--------------------------------------------------------------
        | Table name
        |--------------------------------------------------------------
        |
        */
        'table' => 'users',

        /*
        |--------------------------------------------------------------
        | Primary key name in table
        |--------------------------------------------------------------
        |
        */
        'id' => 'id',
    ],

    /*
    |--------------------------------------------------------------
    | Group entity
    |--------------------------------------------------------------
    |
    */
    'group' => [

        /*
        |--------------------------------------------------------------
        | Model class
        |--------------------------------------------------------------
        |
        */
        'model' => '\App\Group',

        /*
        |--------------------------------------------------------------
        | Table name
        |--------------------------------------------------------------
        |
        */
        'table' => 'groups',

        /*
        |--------------------------------------------------------------
        | Primary key name in table
        |--------------------------------------------------------------
        |
        */
        'id' => 'id',
    ],

    /*
    |--------------------------------------------------------------
    | Privilege entity
    |--------------------------------------------------------------
    |
    */
    'privilege' => [

        /*
        |--------------------------------------------------------------
        | Model class
        |--------------------------------------------------------------
        |
        */
        'model' => '\App\Privilege',

        /*
        |--------------------------------------------------------------
        | Table name
        |--------------------------------------------------------------
        |
        */
        'table' => 'privileges',

        /*
        |--------------------------------------------------------------
        | Primary key name in table
        |--------------------------------------------------------------
        |
        */
        'id' => 'id',
    ],

    /*
    |--------------------------------------------------------------
    | User-Group pivot table
    |--------------------------------------------------------------
    |
    */
    'user_group' => [

        /*
        |--------------------------------------------------------------
        | Table name
        |--------------------------------------------------------------
        |
        */
        'table' => 'group_user',

        /*
        |--------------------------------------------------------------
        | User foreign key in table
        |--------------------------------------------------------------
        |
        */
        'user_id' => 'user_id',

        /*
        |--------------------------------------------------------------
        | Group foreign key in table
        |--------------------------------------------------------------
        |
        */
        'group_id' => 'group_id',
    ],

    /*
    |--------------------------------------------------------------
    | Group-Privilege pivot table
    |--------------------------------------------------------------
    |
    */
    'group_privilege' => [

        /*
        |--------------------------------------------------------------
        | Table name
        |--------------------------------------------------------------
        |
        */
        'table' => 'privilege_group',

        /*
        |--------------------------------------------------------------
        | Group foreign key in table
        |--------------------------------------------------------------
        |
        */
        'group_id' => 'group_id',

        /*
        |--------------------------------------------------------------
        | Privilege foreign key in table
        |--------------------------------------------------------------
        |
        */
        'privilege_id' => 'privilege_id',
    ]

];

Add Panoscape\Privileges\Privilege\UserEntity trait to your user model, Panoscape\Privileges\Privilege\GroupEntity trait to your group model, and Panoscape\Privileges\Privilege\PrivilegeEntity trait to your privilege model.

If you have multiple privileges control flow or you prefer a different profile name, you may copy and modify the default profile template and rename it to something else, admin_profile for example. Then defile a method named profile in your related models and set them to the config name of your choice.

Here is an example of Admin, Role, Permission(instead of User,Group,Privilege):

config/admin_profile.php

<?php

return [
    'user' => [
        'model' => '\App\Admin',
        'table' => 'admins',
        'id' => 'id',
    ],
    'group' => [
        'model' => '\App\Role',
        'table' => 'roles',
        'id' => 'id',
    ],
    'privilege' => [
        'model' => '\App\Permission',
        'table' => 'permissions',
        'id' => 'id',
    ],
    'user_group' => [
        'table' => 'admin_role',
        'user_id' => 'admin_id',
        'group_id' => 'role_id',
    ],
    'group_privilege' => [
        'table' => 'permission_role',
        'group_id' => 'role_id',
        'privilege_id' => 'permission_id',
    ]
];

app/Admin.php

class Admin extends Authenticatable
{
  	...
    use \Panoscape\Privileges\UserEntity;
    
  	public function profile()
    {
        return 'admin_profile';
    }
}

app\Role.php

class Role extends Model
{
  	...
    use \Panoscape\Privileges\GroupEntity;
    
  	public function profile()
    {
        return 'admin_profile';
    }
}

app\Permission.php

class Permission extends Model
{
  	...
    use \Panoscape\Privileges\PrivilegeEntity;
    
  	public function profile()
    {
        return 'admin_profile';
    }
}

Migration

This package does not provide any migrations or commands. You should create three required models/migrations and two pivot tables by yourself. The minimal requirements of table structures are listed in the profile template.

Basic Usage

Access groups/privileges relationship of a user:

$user->groups()->get();
$user->privileges()->get();

or via dynamic properties:

$user->groups->get();
$user->privileges->get();

If you have different entity names other than the default User, Group, Privilege, You should access the relationships by the table values defined in your profile.

Example of Admin, Role, Permission:

$admin->roles()->get();
$admin->roles->get();
$admin->permissions()->get();
$role->admins->get();
$role->permissions->get();
$permission->roles->get();

Group and Privilege validation

has:

//returns true if target group is found on this user
$user->groups()->has('root');

all:

//returns false unless all groups are found on this user
$user->groups()->all(['editor', 'author', 'subscriber']);

any:

//returns true as long as any of these groups are found on this user
$user->groups()->any(['editor', 'author', 'subscriber']);

Instead of the default name column checking, you may specify which column to check:

//check name column by default
$user->groups()->has('root');
//check fullname column instead
$user->groups()->has('Root Administrator', 'fullname');
//check id column instead
$user->groups()->any([1, 3, 5], 'id');

validate:

With this method you can do complex checking

all:

$user->groups()->validate('root|author|subscriber')

equivalent to

$user->groups()->all(['editor', 'author', 'subscriber'])

any:

$user->groups()->validate('(root|author|subscriber)')

equivalent to

$user->groups()->any(['editor', 'author', 'subscriber'])

all + any:

$user->privileges()->validate('query|(delete|insert)|update')

equivalent to

$user->privileges()->all(['query', 'update']) && $user->privileges()->any(['delete', 'insert'])

group:

$user->validate('g=root|(author|subscriber)')

equivalent to

$user->groups()->all(['root']) && $user->groups()->any(['author', 'subscriber'])

privilege:

$user->validate('p=query|(delete|insert)|update')

equivalent to

$user->privileges()->all(['query', 'update']) && $user->privileges()->any(['delete', 'insert'])

group + privilege:

$user->validate('g=root|(author|subscriber);p=query|(delete|insert)|update')

equivalent to

$user->groups()->all(['root']) && $user->groups()->any(['author', 'subscriber'])
  && $user->privileges()->all(['query', 'update']) && $user->privileges()->any(['delete', 'insert'])

Column specification is also available:

$user->validate('g=1|(3|5);p=1|(2|10)|3', 'id')

Middleware

If you have registered the middleware, you can add it to any routes you'd like to guard with it.

Route::get('/pages', 'PageController@index')->middleware('privileges:g=editor|(author|subscriber);p=query|(delete|insert)|update');

Balde

If you have registered the blade service provider, you may guard your blade codes with @validate , @group and @privilege.

Also your user entity need to implement Panoscape\Privileges\Privileged interface in order to use these blade directives.

class Admin extends Authenticatable implements \Panoscape\Privileges\Privileged
{
  	...
    use \Panoscape\Privileges\UserEntity;
}

Blade directives:

@group('root')
  <button>
  	...
  </button>
 @endgroup
  
 @privilege('edit_users')
  <button>
  	...
  </button>
 @endprivilege
  
 @validate('g=(root|editor);p=edit_users')
  <button>
  	...
  </button>
 @endvalidate

Performance

$user->privileges()->validate('editor_users|edit_admins')

joined 5 tables(2 of them are pivot tables) within one query:

select count(*) as aggregate from "permissions" inner join "permission_role" on "permissions"."id" = "permission_role"."permission_id" inner join "roles" on "roles"."id" = "permission_role"."role_id" inner join "admin_role" on "roles"."id" = "admin_role"."role_id" inner join "admins" on "admins"."id" = "admin_role"."admin_id" where "admins"."id" = '1' and "permissions"."name" in ('edit_users', 'edit_admins')
$user->privileges()->validate('edit_users|(create_admins|edit_admins)')

joined 5 tables(2 of them are pivot tables) within two query:

select count(*) as aggregate from "permissions" inner join "permission_role" on "permissions"."id" = "permission_role"."permission_id" inner join "roles" on "roles"."id" = "permission_role"."role_id" inner join "admin_role" on "roles"."id" = "admin_role"."role_id" inner join "admins" on "admins"."id" = "admin_role"."admin_id" where "admins"."id" = '1' and "permissions"."name" in ('create_admins', 'edit_admins')
select count(*) as aggregate from "permissions" inner join "permission_role" on "permissions"."id" = "permission_role"."permission_id" inner join "roles" on "roles"."id" = "permission_role"."role_id" inner join "admin_role" on "roles"."id" = "admin_role"."role_id" inner join "admins" on "admins"."id" = "admin_role"."admin_id" where "admins"."id" = '1' and "permissions"."name" in ('edit_users')
$user->privileges()->validate('(edit_users|delete_users)|(create_admins|edit_admins)')

joined 5 tables(2 of them are pivot tables) within two query:

select count(*) as aggregate from "permissions" inner join "permission_role" on "permissions"."id" = "permission_role"."permission_id" inner join "roles" on "roles"."id" = "permission_role"."role_id" inner join "admin_role" on "roles"."id" = "admin_role"."role_id" inner join "admins" on "admins"."id" = "admin_role"."admin_id" where "admins"."id" = '1' and "permissions"."name" in ('edit_users', 'delete_users')
select count(*) as aggregate from "permissions" inner join "permission_role" on "permissions"."id" = "permission_role"."permission_id" inner join "roles" on "roles"."id" = "permission_role"."role_id" inner join "admin_role" on "roles"."id" = "admin_role"."role_id" inner join "admins" on "admins"."id" = "admin_role"."admin_id" where "admins"."id" = '1' and "permissions"."name" in ('create_admins', 'edit_admins')

Conclusion

Each any group costs one query;

All all group costs one query.