简体   繁体   中英

Laravel 5.1 ACL route resource not working

After following a tutorial on how the built-in acl of laravel works I tried it and it works well by defining every route by itself.

Now I'm trying to use a resource but it's not working as intended. I added the following code to my routes file:

Route::group(['middleware' => 'acl:create_client'], function()
{
    Route::resource('clients', 'ClientController');
});

Now I understand what the problem is:

all the methods in the Clientcontroller will be checked against my db if this user has the acl:create_client, resulting in all methods available to the logged in user that has this acl.

How do I split every method to use it's own acl without having to write it like this:

Route::get('/client/create', [
    'middleware' => 'acl:create_client',
    'as' => 'clients.create',
    'uses' => 'ClientController@create'
]);

Resulting in something like this:

create needs create_client

index needs index_client

update need update_client

etc etc

The bottom line is: you need to setup the 'list' in the Access Control List (ACL) somehow. IMO, the most flexible way would be to pull this list from the database based on the session user; you're off to a good start. You can skip the explicit route assignment by using the already assigned 'as' that you define in a route. An example route:

Route::get('/', ['as'=>'clients.create', 'uses'=>'ClientsController@create']);

Here, you would use the 'clients.create' in your ACL check. Just remember: the ACL will still need the 'as' value set for all your routes (which is good to do anyway).

Step-by-step

Now that you have the required background information, here's how to get it working. These steps assume you were able to correctly setup the tutorial code and database. This will stick to the original tutorial setup and will focus on making the ACL independent from the route configuration.

1) In App\\Http\\Middleware\\Acl\\CheckPermission , you will need to replace the argument $permission = null with the 'as' string that you set in routes.php . The new code:

<?php namespace App\Http\Middleware;

use Closure;

class CheckPermission
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next/*, $permission = null REMOVE THIS*/)
    {
        // Add the next two lines:
        $action = $request->route()->getAction();
        $permission = isset($action['as']) ? $action['as'] : '';

        if (!app('Illuminate\Contracts\Auth\Guard')->guest()) {
            if ($request->user()->can($permission)) {
                return $next($request);
            }
        }

        return $request->ajax ? response('Unauthorized.', 401) : redirect('/login');
    }
}

2) Now, you need to assign this middleware in a different manner. You do not want to use a specific permission, but instead use the 'as' string we just setup in the middleware. You can assign the middleware in two different ways: a) assign it to a group of routes, or b) assign it to every page. I suggest using 2a instead of 2b, because you may not want to use the ACL on all routes.

2a) Here's the method to assign it to only a group of routes. The two important things to notice here are the 'as'=>'clients.*' strings and the assignment of the middleware to the route group 'middleware' => 'acl' . Also note this route group does not pass the extra string parameter like the tutorial does (eg 'middleware' => 'acl:manage_user' ). This is because we removed that argument from the handle() function above. You will need to change these example routes to match your target URIs and controller functions.

Route::group(['middleware' => 'acl'], function()
{
    Route::get('/clients', ['as'=>'clients.view', 'uses'=>'ClientsController@index']);
    Route::get('/clients/new', ['as'=>'clients.create', 'uses'=>'ClientsController@create']);
    // Add more routes ...
}

2b) Here's how to assign it to every page. The tutorial uses the file /app/Http/Kernel.php to setup the middleware as a $routeMiddleware . This is the correct way to do it for step 2a above, but not if you want it on every page. To make the middleware a global middleware: add '\\App\\Http\\Middleware\\CheckPermission' to the $middleware variable found in the same file. You will not need the $routeMiddleware addition from the tutorial if you use the global variable.

3) In the tutorial database, you need to use the 'as' string in the permissions table within the permission_slug column. Here are example SQL inserts that allows user with id 123 to access route clients.create . These two create the permission and role we need to create access to the 'client.create' route.

INSERT INTO permissions ('permission_title', 'permission_slug', 'permission_description')
    VALUES ('Create a Client', 'clients.create', 'Allow the user to create a client');

INSERT INTO roles ('role_title', 'role_slug')
    VALUES ('Client Admin', 'clients.admin');

For the next query, you need to know the id of the two rows above. This assumes your database was newly created with no rows yet added, so each of the inserts will be id=1 . This says: permission with id=1 is assigned to role with id=1 .

INSERT INTO permission_role ('permission_id', 'role_id') VALUES (1, 1);

The next query also assumes the new role will be id=1 and the user id is 123 . This assigns the new role with id=1 to the existing user with id=123 .

INSERT INTO role_user ('role_id', 'user_id') VALUES (1, 123);

At this point, you should have a user with id=123 that has the Client Admin role. The Client Admin role should have the 'clients.create' permission. When you are logged in as user id=123 , you will be verified to have the 'clients.create' permission, and you should be able to access the page ( example.com/clients/new in my example). Any other user will not have access, and they will be redirected to the login page (this doesn't make sense to me if you're already logged in; this is just what the tutorial setup).

I recommend you do not build acl by yourself,there have some good packages out there like entrust

and if you truly want know the principle or laravel acl just follow this video tutorial from laracast laracast laravel acl tutorial

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM