Laravel 5.1 ACL路由资源无法正常工作

4

在学习了Laravel内置的acl如何工作的教程之后,我尝试了一下,并通过为每个路由单独定义来使其正常工作。

现在我正在尝试使用资源,但它并没有按预期工作。我在我的路由文件中添加了以下代码:

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

现在我明白问题所在了:Clientcontroller中的所有方法都将根据我的数据库检查此用户是否具有acl:create_client,导致所有方法对已登录并具有此acl的用户可用。
我该如何拆分每个方法以使用它自己的acl,而不必像这样编写它:
Route::get('/client/create', [
    'middleware' => 'acl:create_client',
    'as' => 'clients.create',
    'uses' => 'ClientController@create'
]);

结果会像这样:

create 需要 create_client

index 需要 index_client

update 需要 update_client

等等等等


这样明确声明有什么问题吗?另外,想象一下如果您完全掌控了这个——您会如何看待它,是否有现有语法中需要摆脱的东西? - Denis Mysenko
通过显式地执行,我认为它不够“简洁”。你在第二个问题中指的是什么? - davejal
我的意思是,想象一下你可以按任何你想要的方式编写它。你真的会让它更短/更简单吗?除了重复“uses”部分(甚至那也不完全如此) - 我并没有看到太多的重复!而且,正如人们所说,routes.php是一份文档,当它像这样明确时 - 它是一份好的文档。 - Denis Mysenko
那么您实际上建议明确创建所有路由?所以,如果我有10个模型,如果每个模型都有创建、更新和删除功能,我将不得不创建30个路由?还有不同的授权级别(具有不同角色的不同类型用户)。 - davejal
2个回答

2
底线是:你需要在访问控制列表(ACL)中设置“list”。个人认为,最灵活的方式是基于会话用户从数据库中提取此列表;你已经有了良好的开端。您可以通过使用在路由中定义的已分配的“as”来跳过显式路由分配。例如路由:

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

在这里,您将在ACL检查中使用'clients.create'。只需记住:所有路由都需要设置'as'值(这样做也很好)。

逐步指南

现在您已经获得了所需的背景信息,接下来是如何使其正常工作的方法。这些步骤假设您能够正确设置教程代码和数据库。这将坚持原始的教程设置,并专注于使ACL独立于路由配置。

1)在App\Http\Middleware\Acl\CheckPermission中,您需要将参数$permission = null替换为在routes.php中设置的'as'字符串。新代码:

<?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) 现在,您需要以不同的方式分配此中间件。 您不想使用特定权限,而是使用我们刚刚设置的 'as' 字符串中的内容。 您可以有两种不同的方式来分配中间件:a)将其分配给一组路由,或者b)将其分配给每个页面。 我建议使用2a而不是2b,因为您可能不想在所有路由上使用ACL。

2a) 这是仅将其分配给一组路由的方法。 在此处注意到的两个重要事项是 'as'=>'clients.*' 字符串和将中间件分配给路由组 'middleware' => 'acl'。 还请注意,此路由组不像教程中那样传递额外的字符串参数(例如 'middleware' => 'acl:manage_user')。 这是因为我们从上面的 handle() 函数中删除了该参数。 您需要更改这些示例路由以匹配您的目标URI和控制器函数。

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)以下是如何将其分配给每个页面的方法。本教程使用文件/app/Http/Kernel.php来设置中间件作为$routeMiddleware。这是在步骤2a中正确的方法,但如果您想将其应用于每个页面,则不是正确的方法。要将中间件设置为全局中间件:请将'\App\Http\Middleware\CheckPermission'添加到同一文件中找到的$middleware变量中。如果使用全局变量,则无需使用教程中的$routeMiddleware添加。

3) 在教程数据库中,您需要在permissions表中的permission_slug列中使用字符串'as'。以下是示例SQL插入,允许具有id 123的用户访问路径clients.create。这两个创建了我们需要创建对'client.create'路由的访问权限的权限和角色。

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');

对于下一个查询,您需要知道上面两行的id。这假设您的数据库是新创建的,尚未添加任何行,因此每个插入都将是id=1。这意味着:将权限id=1分配给角色id=1

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

下一个查询还假设新角色将是id=1,用户id是123。这将把id=1的新角色分配给现有的id=123用户。

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

此时,您应该拥有一个id为123的用户,并拥有"客户管理员"角色。 "客户管理员"角色应该拥有"clients.create"权限。当您以id为123的用户身份登录时,您将被验证是否具有"clients.create"权限,并且您应该能够访问页面(例如,在我的示例中是example.com/clients/new)。任何其他用户将无法访问该页面,并将被重定向到登录页面(如果您已经登录,则这没有意义;这只是教程设置的一部分)。

这很详细,但我需要一些时间来理解这个想法。在我做这件事的时候,你可以解释一下所需的数据库结构,或者至少那些不相似的部分吗? - davejal
我的数据库和教程数据库之间的差异微不足道;结构的重要方面是相同的。我代码中真正重要的部分是在路由使用 'as' 而不是在路由中明确定义单个权限时。你需要做的是将权限 slug 与路由别名匹配以确认对资源的权限。 - Siphon
是的,我有点迷茫,对Laravel还很新,已经在尝试中级的东西了... - davejal
抱歉耽误了时间。我完全改变了我的问题的格式,现在采用逐步说明的方式。 - Siphon
没问题,它看起来很有前途。我今晚会测试它。 - davejal
显示剩余6条评论

0

我建议你不要自己建立acl,因为有很多好的包可供使用,例如entrust

如果你真的想了解laravel acl的原理,可以跟随laracast提供的视频教程laracast laravel acl tutorial


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接