E
E
Eugene2016-04-30 14:47:19
Laravel
Eugene, 2016-04-30 14:47:19

How to control access levels for Admin Architect - Laravel 5.2 modules?

I made an admin panel in Admin Architect, but I have no idea how to prohibit a certain group of users from accessing certain modules.
Usually Middleware is used for this, but the problem is that the admin routes are too abstract:

<?php

$pattern = '[a-z0-9\_\=]+';

Route::group([
    'prefix'    => 'area',
    'namespace' => 'Terranet\Administrator',
    'middleware'=> ['web'],
], function () use ($pattern) {
    /*
    |-------------------------------------------------------
    | Authentication
    |-------------------------------------------------------
    */
    Route::get('login', [
        'as'   => 'scaffold.login',
        'uses' => '[email protected]',
    ]);

    Route::post('login', '[email protected]');

    Route::get('logout', [
        'as'   => 'scaffold.logout',
        'uses' => '[email protected]',
    ]);

    /*
    |-------------------------------------------------------
    | Main Scaffolding routes
    |-------------------------------------------------------
    */
    Route::group(['prefix'    => 'admin',], function () use ($pattern) {
        /*
        |-------------------------------------------------------
        | Custom routes
        |-------------------------------------------------------
        |
        | Controllers that shouldn't be handled by Scaffolding controller
        | goes here.
        |
        */
        //        Route::controllers([
        //            'test' => 'App\Http\Controllers\Admin\TestController'
        //        ]);

        /*
        |-------------------------------------------------------
        | Scaffolding routes
        |-------------------------------------------------------
        */
        // Dashboard
        Route::get('/', [
            'as'   => 'scaffold.dashboard',
            'uses' => '[email protected]',
        ]);

        // Index
        Route::get('{module}', [
            'as'   => 'scaffold.index',
            'uses' => '[email protected]',
        ])->where('module', $pattern);

        // Create new Item
        Route::get('{module}/create', [
            'as'   => 'scaffold.create',
            'uses' => '[email protected]',
        ])->where('module', $pattern);
        //и т.д.
    });
});

I called the middleware from the module itself in the constructor:
<?php

namespace App\Http\Terranet\Administrator\Modules;

use Terranet\Administrator\Contracts\Module\Editable;
use Terranet\Administrator\Contracts\Module\Exportable;
use Terranet\Administrator\Contracts\Module\Filtrable;
use Terranet\Administrator\Contracts\Module\Navigable;
use Terranet\Administrator\Contracts\Module\Sortable;
use Terranet\Administrator\Contracts\Module\Validable;
use Terranet\Administrator\Resource;
use Terranet\Administrator\Traits\Module\AllowFormats;
use Terranet\Administrator\Traits\Module\HasFilters;
use Terranet\Administrator\Traits\Module\HasForm;
use Terranet\Administrator\Traits\Module\HasSortable;
use Terranet\Administrator\Traits\Module\ValidatesForm;

/**
 * Administrator Resource Accounts
 *
 * @package Terranet\Administrator
 */
class Accounts extends Resource implements Navigable, Filtrable, Editable, Validable, Sortable, Exportable
{
    use HasFilters, HasForm, HasSortable, ValidatesForm, AllowFormats;

    /**
     * The module Eloquent model
     *
     * @var string
     */

    protected $model = 'reg2005\\PayAssetsLaravel\\Entities\\Accounts';

    public function __construct()
    {
        $this->middleware('OnlyCli');
    }
}

This caused an error: Fatal error: Call to undefined method App\Http\Terranet\Administrator\Modules\Accounts::middleware (
)
figured out how to properly connect it to the module.
UPD: I tried to block access through the action service. I had to describe all sorts of actions: canEdit, canView, canIndex, etc. This successfully blocked the desired module, but this approach is redundant. Too much writing, it's easier then like this:
$this->middleware('OnlyRoot', ['only' => ['canEdit', 'canDelete'] ] );

I have 2 questions for you:
1. How to properly extend the class so that I can use the middleware from the Module/Action Admin Architect?
2. Are there alternative ways to control access to modules?

Answer the question

In order to leave comments, you need to log in

1 answer(s)
T
terzi_eduard, 2016-05-12
@terzi_eduard

Good afternoon!
I immediately apologize for the long silence.
I will try to answer your questions briefly, but meaningfully.
At the moment, you can manage access in 2 ways:
file `config/administrator.php` contains the `permission` key, where you can specify global access levels to the admin area as a whole.

'permission' => function ()
{
  return ($auth = auth('admin')->user()) && $auth->isSuperAdmin();
},

Each module (resource) in Admin Architect has a default Action Service - a class responsible for performing CRUD tasks. The Action Service is also used to declare bulk actions and single actions.
As you rightly noted, the routes in Admin Architect are quite abstract, so there are certain difficulties with setting Middleware for a specific resource. That is why this task fell on the shoulders of Action Servic.
Those. to determine the access level for a specific action in a resource, it is enough to write the `can` method.
public function canEdit(Authenticatable $who, $model)
{
  return $user->isSuperAdmin() && ! $model->isProtected();
}

also for global policy, you can use a third-party service class:
public function canEdit(Authenticatable $user, $model)
{
  return (new ACLGate($user))->forEntity($model)->checkPermission('edit');
}

another option: each Action Service created for a resource can be inherited not from `Terranet\Administrator\Services\Actions`, but from its own Proxy class (`php artisan administrator:action `), with certain ACL logic, or you can try completely replace `app('scaffold.actions')` with your own implementation.
If you have a fairly flexible ACL policy - this is quite convenient, although you have to add a little, in a normal situation, you can describe fairly general rules like this (the example is quite simple, but reflects the essence of the approach):
public function __call($method, $args)
{
  if (in_array($method, ['canEdit', 'canActivate', 'canLock'])) {
    list($user, $model) = each($args);
    return $user->isSuperAdmin() && ! $model->isProtected();
  }

  return false;
}

Of the advantages of this approach in relation to middleware - for single-action methods (canEdit, canDelete, your own) it allows you to control access at the level of a specific record, and not just the resource as a whole.
For example, it is easy to disable the deletion of a user with the status 'SuperAdmin'.
I hope I wrote not in vain, and it will be useful to someone!
PS Of course, the presented solutions are not ideal, they can and should be improved, but they fulfill the task. At a leisure I will think how it is possible to improve the given model. If you have any suggestions, I'll be happy to take them into consideration.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question