【问题标题】:Laravel 5.1 ACL route resource not workingLaravel 5.1 ACL 路由资源不起作用
【发布时间】:2016-04-20 12:40:51
【问题描述】:

在关注 tutorial 关于 laravel 的内置 acl 的工作原理之后,我尝试了它,它通过自己定义每条路由而运行良好。

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

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

现在我明白了问题所在:

如果此用户具有 acl:create_client,则将针对我的数据库检查 Clientcontroller 中的所有方法,从而使具有此 acl 的登录用户可用的所有方法。

如何拆分每个方法以使用它自己的 acl 而不必像这样编写:

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

结果如下:

创建需求 create_client

索引需要 index_client

更新需要 update_client

等等等等

【问题讨论】:

  • 这样的显式声明有什么问题?另外,想象一下你对此有完全的控制权——你会如何看待它,在现有的语法中真的有什么可以摆脱的吗?
  • 通过明确地这样做,我虽然它不像 clean 那样。您在第二个问题中的意思或指的是什么?
  • 我的意思是,想象一下你可以用任何你想要的方式来编写它。你真的会让它更短/更简单吗?除了重复“使用”部分(甚至那个 - 不完全) - 我看不到太多重复!此外,正如人们所说,routes.php 是一个文档,当它像这样明确时 - 它是一个很好的文档。
  • 所以您实际上是在建议明确创建所有路线?所以如果我有 10 个模型,如果每个模型都有创建、更新和删除,我将不得不创建 30 条路线?以及不同的授权级别(具有不同角色的不同类型的用户)。

标签: php routes laravel-5.1 acl laravel-routing


【解决方案1】:

底线是:您需要以某种方式在访问控制列表 (ACL) 中设置“列表”。 IMO,最灵活的方法是根据会话用户从数据库中提取此列表;你有一个好的开始。您可以使用您在路由中定义的已分配的'as' 跳过显式路由分配。示例路线:

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

在这里,您将在 ACL 检查中使用'clients.create'。请记住:ACL 仍然需要为您的所有路由设置 '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'=&gt;'clients.*' 字符串和将中间件分配给路由组'middleware' =&gt; 'acl'。另请注意,此路由组不会像教程那样传递额外的字符串参数(例如'middleware' =&gt; '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) 在教程数据库中,您需要在permission_slug 列内的permissions 表中使用'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);

此时,您应该拥有具有Client Admin 角色的id=123 用户。 Client Admin 角色应具有 'clients.create' 权限。当您以用户id=123 登录时,您将被验证拥有'clients.create' 权限,并且您应该能够访问该页面(在我的示例中为example.com/clients/new)。任何其他用户将无权访问,他们将被重定向到登录页面(如果您已经登录,这对我来说没有意义;这正是教程设置的内容)。

【讨论】:

  • 这很详细,但我需要一些时间来掌握这个想法。当我这样做时,你能解释一下所需的数据库结构,或者至少是不相似的部分吗?
  • 我的数据库和教程数据库的差别不大;结构的重要方面是相同的。我的代码中真正重要的部分是它使用路由的'as',而不是显式定义路由中的各个权限。您需要做的是将权限 slug 与路由别名匹配以确认对资源的权限。
  • 并进一步解释。我的User::hasPermission(Auth::user()-&gt;id, $action_alias) 可以替换为教程$request-&gt;user()-&gt;can($permission),其中$permission 应该是我的$action_alias
  • 我在尝试实现这一点时有点迷茫,他们是否可以通过某种方式更好地解释路线(指一步一步或聊天室),或者我应该提供更多详细信息我正在做,虽然它很简单。
  • 我稍后会逐步添加。
【解决方案2】:

我建议你不要自己构建 acl,那里有一些不错的包,比如entrust

如果你真的想知道 laravel acl 的原理或原理,请按照 laracast laracast laravel acl tutorial 的这个视频教程进行操作

【讨论】:

    猜你喜欢
    • 2015-08-09
    • 2015-12-13
    • 2020-12-29
    • 1970-01-01
    • 2016-10-20
    • 1970-01-01
    • 1970-01-01
    • 2016-07-09
    • 2015-10-27
    相关资源
    最近更新 更多