Skip to content

Commit

Permalink
Merge branch 'ManyRoles'
Browse files Browse the repository at this point in the history
  • Loading branch information
dlnsk committed Jan 15, 2020
2 parents e4a2417 + dc2d66a commit 1417968
Show file tree
Hide file tree
Showing 14 changed files with 367 additions and 36 deletions.
10 changes: 9 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,15 @@ All Notable changes to `h-rbac` will be documented in this file.

Updates should follow the [Keep a CHANGELOG](http://keepachangelog.com/) principles.

## [0.1] - 2016-03-14
## [0.4.0] - 2020-01-15
### Added
- Support for multiply roles (many-to-many relationship). Backward compatible.
- Covered by tests.

## [0.3.4] - 2019-10-24
### Changed
- Since Laravel 5.7 helpers was changed

## [0.1] - 2016-03-14
### Added
- Initial version
12 changes: 11 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ Add the service provider to `config/app.php`. We use auto-discovering feature si
Publish some cool stuff:

- config file (config/h-rbac.php)
- migration (add field `role` to `users` table)
- migration (adding field `role` to `users` table), only if you suppose to use one role per user
- role/permission/callbacks configuration class (app/Classes/Authorization/AuthorizationClass.php)

with
Expand All @@ -42,6 +42,16 @@ with

Add roles, permissions which you need and callbacks where it needs and have fun!

### Many To Many with roles

If you want to use "Many To Many" relationship between users and roles add an accessor to `User` model. Name of attribute you can change in `config/h-rbac.php` if you need:

``` php
public function getOwnRolesAttribute() {
return $this->roles()->pluck('name')->toArray();
}
```

## Overview

This module is wrapper for [authorization logic](https://laravel.com/docs/5.2/authorization#checking-abilities) and control access to resources of Laravel 5.1 and later. Except you shouldn't define abilities, they will define automatically.
Expand Down
3 changes: 2 additions & 1 deletion config/exampleClass.php → classes/AuthorizationClass.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ public function getRoles() {
*/

public function editOwnPost($user, $post) {
$post = $this->getModel(\App\Post::class, $post); // helper method for geting model
// This is a helper method for getting the model if $post is id
// $post = $this->getModel(\App\Post::class, $post);

return $user->id === $post->user_id;
}
Expand Down
13 changes: 10 additions & 3 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,21 @@
}
],
"require": {
"illuminate/support": "~5.7|>=6.0"
"laravel/framework": "~5.7|>=6.0"
},
"require-dev": {
"phpunit/phpunit": "~4.5"
"phpunit/phpunit": "^8.0",
"orchestra/testbench": "^4.5"
},
"autoload": {
"psr-4": {
"Dlnsk\\HierarchicalRBAC\\": "src"
"Dlnsk\\HierarchicalRBAC\\": "src",
"App\\Classes\\Authorization\\": "classes"
}
},
"autoload-dev": {
"psr-4": {
"Dlnsk\\HierarchicalRBAC\\Tests\\": "tests"
}
},
"extra": {
Expand Down
8 changes: 7 additions & 1 deletion config/config.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?php return [

/*
|--------------------------------------------------------------------------
| Package Configuration Option
Expand All @@ -8,4 +8,10 @@

'rbacClass' => App\Classes\Authorization\AuthorizationClass::class,

/**
* Name of user's class attribute that gives array of roles
* if you uses many-to-many relationship
*/

'userRolesAttribute' => 'own_roles',
];
Empty file removed database/migrations/.gitkeep
Empty file.
1 change: 0 additions & 1 deletion phpunit.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false"
syntaxCheck="false"
bootstrap="./vendor/autoload.php"
>
<testsuites>
Expand Down
46 changes: 32 additions & 14 deletions src/ArrayAuthorization.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace Dlnsk\HierarchicalRBAC;

use Illuminate\Support\Str;
use Illuminate\Support\Arr;


class ArrayAuthorization
Expand Down Expand Up @@ -36,26 +37,15 @@ private function testUsingUserMethod($user, $initial_ability, $current_ability,
*
* @return boolean
*/
public function checkPermission($user, $ability, $arguments)
public function checkAbility($user, $user_abilities, $ability, $arguments)
{
if ($user->role === 'admin') {
return true;
}

// У пользователя роль, которой нет в списке
$roles = $this->getRoles();
if (!isset($roles[$user->role])) {
return null;
}

// Ищем разрешение для данной роли среди наследников текущего разрешения
$role = $roles[$user->role];
$permissions = $this->getPermissions();
$current = $ability;
// Если для разрешения указана замена - элемент 'equal', то проверяется замена
// (только при наличии оригинального разрешения в роли).
// Callback оригинального не вызывается.
if (in_array($current, $role) and isset($permissions[$current]['equal'])) {
if (in_array($current, $user_abilities) and isset($permissions[$current]['equal'])) {
$current = $permissions[$current]['equal'];
}

Expand All @@ -66,7 +56,7 @@ public function checkPermission($user, $ability, $arguments)
throw new \Exception("Seems like permission '{$ability}' is in infinite loop");
}

if (in_array($current, $role)) {
if (in_array($current, $user_abilities)) {
$suitable = $suitable || $this->testUsingUserMethod($user, $ability, $current, $arguments);
}
if (isset($permissions[$current]['next']) and !$suitable) {
Expand All @@ -79,6 +69,34 @@ public function checkPermission($user, $ability, $arguments)
}


public function checkPermission($user, $ability, $arguments)
{
$attribute = config('h-rbac.userRolesAttribute');
$user_roles = Arr::wrap($user->role ?? null) ?: Arr::wrap($user->$attribute ?? null);

if (in_array('admin', $user_roles)) {
return true;
}

// У пользователя роли, которых нет в списке ролей приложения
$application_roles = array_keys($this->getRoles());
$both_roles = array_intersect($application_roles, $user_roles);
if (!count($both_roles)) {
return null;
}

$abilities = $this->getRoles();
$user_abilities = [];
foreach ($both_roles as $role_name) {
$user_abilities = array_merge($user_abilities, $abilities[$role_name]);
}
$result = $this->checkAbility($user, $user_abilities, $ability, $arguments);

return is_bool($result) ? $result : null;
}



/**
* Return model of given class or exception if can't
*
Expand Down
34 changes: 20 additions & 14 deletions src/HRBACServiceProvider.php
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<?php
<?php
namespace Dlnsk\HierarchicalRBAC;

use Illuminate\Support\ServiceProvider;
Expand All @@ -12,7 +12,7 @@
class HRBACServiceProvider extends ServiceProvider {

/**
* This will be used to register config & view in
* This will be used to register config & view in
* package namespace.
*/
protected $packageName = 'h-rbac';
Expand All @@ -24,18 +24,21 @@ class HRBACServiceProvider extends ServiceProvider {
*/
public function boot()
{
// Register your migration's publisher
$this->publishes([
__DIR__.'/../database/migrations/' => base_path('database/migrations')
], 'migrations');

// Publish your config
$this->publishes([
__DIR__.'/../config/config.php' => config_path($this->packageName.'.php'),
__DIR__.'/../config/exampleClass.php' => app_path('Classes/Authorization/AuthorizationClass.php'),
], 'config');
if ($this->app->runningInConsole()) {

//
// Register your migration's publisher
$this->publishes([
__DIR__ . '/../database/migrations/add_role_field_to_users.stub'
=> database_path('migrations/' . date('Y_m_d_His', time()) . '_add_role_field_to_users.php'),
], 'migrations');

// Publish your config
$this->publishes([
__DIR__.'/../config/config.php' => config_path($this->packageName.'.php'),
__DIR__.'/../classes/AuthorizationClass.php' => app_path('Classes/Authorization/AuthorizationClass.php'),
], 'config');

}
}

/**
Expand All @@ -55,7 +58,10 @@ public function register()

$this->app->afterResolving('blade.compiler', function (BladeCompiler $bladeCompiler) {
$bladeCompiler->directive('role', function ($roles) {
return "<?php if(auth()->check() && in_array(auth()->user()->role, explode('|', $roles))): ?>";
return '<?php
$__attribute = config("h-rbac.userRolesAttribute");
$__user_roles = Arr::wrap(auth()->user()->role ?? null) ?: Arr::wrap(auth()->user()->$__attribute ?? null);
if(auth()->check() && array_intersect($__user_roles, explode("|", '.$roles.'))): ?>';
});
$bladeCompiler->directive('endrole', function () {
return '<?php endif; ?>';
Expand Down
Empty file removed tests/.gitkeep
Empty file.
31 changes: 31 additions & 0 deletions tests/TestCase.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

namespace Dlnsk\HierarchicalRBAC\Tests;

use Dlnsk\HierarchicalRBAC\HRBACServiceProvider;


abstract class TestCase extends \Orchestra\Testbench\TestCase
{
/**
* Setup the test environment.
*/
public function setUp(): void
{
parent::setUp();
}


/**
* @param \Illuminate\Foundation\Application $app
*
* @return array
*/
protected function getPackageProviders($app)
{
return [
HRBACServiceProvider::class,
];
}

}
Loading

0 comments on commit 1417968

Please sign in to comment.