mnabialek/laravel-authorize

允许基于角色或权限授权用户

v1.2.2 2017-09-26 12:51 UTC

This package is not auto-updated.

Last update: 2024-09-14 19:03:59 UTC


README

此模块使得管理用户对Laravel应用程序不同部分的访问变得简单。您可以使用基于用户角色或用户权限的 authorize 中间件来保护您的路由,而无需在控制器中添加任何额外的代码,以保持其尽可能简洁,就像没有使用授权一样。

支持版本

要在Laravel 5.4+ 中安装,请使用此分支,但要在Laravel >= 5.1 且 Laravel < 5.4 中安装,请参阅 版本 1.1

安装

  1. 在控制台运行

    composer require mnabialek/laravel-authorize 1.2.*

    以安装此模块

  2. 打开 config/app.php

  • 注释掉以下行

    Illuminate\Auth\AuthServiceProvider::class,
  • 添加

     Mnabialek\LaravelAuthorize\Providers\Auth::class,
     Mnabialek\LaravelAuthorize\Providers\Authorize::class,

    在相同的部分(providers)中

  1. 在控制台运行

    php artisan vendor:publish --provider="Mnabialek\LaravelAuthorize\Providers\Authorize"

    在您的控制台中发布默认配置文件、中间件、基础策略类和未授权视图

  2. app/Http/Kernel.php$routeMiddleware 中添加

    'authorize' => \App\Http\Middleware\Authorize::class,

    以注册 Authorize 中间件

  3. 打开 App\Http\Middleware\Authorize.php 并根据您的需求调整 errorResponsereportUnauthorizedAttempt。如果默认值符合您的需求,请打开 resources/views/errors/401.blade.php 并根据您的需求调整此模板 - 默认情况下,如果用户没有给定路由的权限,将使用此视图。

  4. 打开您的 User.php 模型文件

    use Mnabialek\LaravelAuthorize\Contracts\Roleable as RoleableContract;

    在类定义之前添加

    implements ..., RoleableContract

    使 User 类实现此接口,因此它应该看起来像这样

  5. 作为 ... 您应该保留此 User 类实现的全部默认接口。

    use \Mnabialek\LaravelAuthorize\Traits\Roleable;

    确保您的 User 类实现了 Roleable 接口。为了做到这一点,您需要实现2个方法: hasRolegetRoles。为了简化,您可以使用默认的 Roleable 特性。只需在您的 User 类中放入

    public function getRoles()
    {
        return $this->role ? [$this->role->slug]: [];
    }

    请注意,此特性假定您为 User 模型有 role 属性(这意味着您在数据库的 users 表中有 role 列,该列存储您的角色名称)。在许多情况下,这不会成立,因此您需要至少覆盖 getRoles 方法以获取有效的用户角色。假设您有一个一对一的 role 关系(用户只分配给单个角色),自定义实现可能如下所示

启动

此模块允许您使用 authorize 中间件来保护您的路由。您有两种方法可以使用此中间件(您可以在同一应用程序中使用这两种方法) - 基于角色或基于权限。

使用此模块,您可以同时为授权用户和非授权用户设置权限,以保持授权层的一致性。

1. 基于角色的授权

您可以指定带有参数的中间件,例如 authorize:manager,employee - 在这种情况下,只有用户角色会被验证。在这个例子中,如果用户具有任何角色 manageremployee,他们将被允许访问路由,否则他们不会被允许这样做。然而,在上面的例子中,具有 super_roles 的用户也会被允许这样做(super_rolesconfig/authorize.php 中)。所以如果您在 super_roles 中也定义了 admin,那么具有 admin 角色的用户也将被允许访问此路由,因此如果您指定了其他角色,您就不需要指定 admin 角色了(但当然,如果您想这么做也可以)。

使用此模式不需要进行更多配置。

2. 基于权限的授权

在此选项中,您不能在由 authorize 中间件保护的路由中使用闭包。确保您在这些路由中不要使用它们,否则在应用 authorize 中间件时您将遇到异常。

如果您使用不带任何参数的中间件,例如 authorize,它将利用 Laravel 授权 并对此机制进行一些额外更改。默认情况下,Laravel 建议为模型创建策略,但在某些情况下,使用控制器的策略可能更合理,这正是本模块所做的事情。

配置

打开 config/authorize.php 文件,并在 super_roles 中放置允许执行任何操作的角色的名称,这样就不需要进行额外的检查。在大多数情况下,将 admin 角色放在这里是合理的,但在某些情况下,如果您想运行详细规则模式,您可能希望将其留空。将您在应用程序中使用的所有角色都放入 permissions 部分的 roles 部分。

保护您的控制器

假设我们有一个名为 UserController 的控制器,它具有默认的 REST 操作 - indexshowcreatestoreeditupdatedestroy,并且我们希望使用 authorize 中间件来保护此控制器,因为我们不希望所有用户都能允许此控制器中的所有操作。

首先,我们需要打开 app\Providers\AuthServiceProvider.php 文件,并在 $policies 属性中添加我们控制器的策略映射。

\App\Http\Controllers\UserController::class => \App\Policies\UserControllerPolicy::class,

现在,让我们在 app/Policies/UserControllerPolicy.php 文件中创建 Policy 类,其定义如下

<?php

namespace App\Policies;

class UserControllerPolicy extends BasePolicyController
{
  protected $group = 'user';
}

现在,您需要打开 config/authorize.php 文件,并在 permissions 部分的 available 部分中添加您需要用于保护每个控制器方法的权限。默认情况下,权限的格式为 $group . controller method。我们在 UserControllerPolicy 中定义了组为 user,在我们的控制器中我们有以下方法:indexshowcreatestoreeditupdatedestroy,所以我们的权限默认看起来应该是这样的

'user.index',
'user.show',
'user.create',
'user.store',
'user.edit',
'user.update',
'user.destroy',

但事实上,在大多数情况下,您根本不需要对 create 进行权限。用户只有在具有运行 store 方法的权限时才能运行控制器的 create 方法。同样的情况也适用于 edit - 他们只有在具有运行 update 方法的权限时才能运行 edit(这种行为可以修改 - 查看 Customization),所以让我们只添加以下权限到这些部分

'user.index',
'user.show',
'user.store',
'user.update',
'user.destroy',

现在,是时候为不同的角色设置这些权限了。在 permissions 部分的 roles 部分中,您有一些示例角色。您应该将此处放置与您的系统角色名称匹配的角色,并将任何这些权限分配给它们。对于 admin 用户,通常您希望允许一切,因此您可以只添加 * 作为权限,这意味着 admin 角色将拥有在 available 部分中定义的所有权限。

现在请确保,你在routes.php中将authorize中间件应用到UserController上,例如这样做:

Route::group(['middleware' => ['authorize']],
  function () {        
      Route::resource('users', 'UserController');
  });

就这些了!你已经用authorize中间件保护了第一个控制器。

如果你还想保护另一个控制器,只需重复这些步骤。当然,你需要确保你在新的策略类中设置$group属性为唯一的值。

高级使用

默认情况下,如前所述,你可以为控制器创建一个非常简单的策略类,就这样。然而在实际应用中,你可能想使用更复杂的规则来验证用户是否可以访问给定的控制器方法。例如,用户可能有更新用户的权限,但他们只能更新自己的账户。

授权验证的默认流程如下

  • 如果用户未登录,将为其应用设置为guest_role_name(默认为匿名)的角色值
  • 如果用户具有超级角色(你可以在config/authorize.php中的super_roles部分进行配置),则他们将有权访问任何内容,并且不会运行任何自定义方法
  • 如果用户没有必要的权限,则不会进行进一步检查
  • 如果用户有必要的权限,我们将验证策略中是否有针对能力的自定义方法(方法名称应与控制器中的方法名称匹配)。如果没有,用户将被允许运行此操作
  • 然而,如果策略中有针对能力的自定义方法,用户是否可以运行此操作将取决于自定义方法对此能力的返回结果。

假设我们有一个这样的路由

Route::show('/users/{users}/{type}', 'UserController@show')

并且我们只想允许管理员角色显示所有用户,而其他人只能显示自己的账户。

我们可以在RouteServiceProvider.php中注册以下路由模型绑定

$router->model('users', 'App\User');

因此,现在在我们的UserControllerPolicy类中,我们可以创建以下方法

public function show($user, $displayedUser, $type)
{
  if ($displayedUser->id == $user->id) {
      return true;
  }
  return false;
}

现在,这个额外的方法将在验证用户有user.show权限后使用。因为在上述情况下,我们假设我们有super_roles中的管理员角色,这就是我们在这里需要使用的。

当然,你也可以在这里使用$type参数,或者直接使用请求参数(如果它们应该影响授权)使用getRequest()方法,或者直接使用$request属性。

请注意,在上面的例子中,我们假设$user是User对象。然而,如果我们允许未授权用户访问此路由,我们应该修改代码来处理这种情况。假设我们希望允许未授权用户查看任何用户,而授权用户只能查看自己的资料。在这种情况下,我们应该像这样修改方法的代码

public function show($user, $displayedUser, $type)
{
  if (!$user || $displayedUser->id == $user->id) {
      return true;
  }
  return false;
}

定制

默认情况下,所有createedit能力都将自动替换为storeupdate,因为在大多数情况下这将是所需的行为。然而,如果你不想这样使用它,或者你想创建自定义能力映射,只需打开app/Policies/BasePolicyController类并创建自定义的getAbilityMappings方法。当然,你也可以在单个策略类中这样做,例如UserControllerPolicy

此外,在某些情况下,你可能会希望在两个不同控制器的不同方法中使用相同的权限。然后你可以在你的策略类之一中创建自定义的getPermissionMappings方法,例如

protected function getPermissionMappings()
{
  return ['store' => 'somethingelse.store];
}

这样,你可以使用不基于当前策略类分配的group的权限。

高级定制

此模块使用以下接口的默认实现

  • Mnabialek\LaravelAuthorize\Contracts\Permissionable
  • Mnabialek\LaravelAuthorize\Contracts\PermissionHandler

但在某些情况下,你可能需要覆盖默认实现或创建自定义实现。例如,你可能想使用自定义数据库处理程序来在数据库中存储权限。

因此,如果你想创建自定义实现,只需实现这两个接口之一,并在 config/authorize.php 文件中的 bindings 部分设置这些接口的自定义绑定。

许可证

本软件包采用 MIT 许可证