mnabialek / laravel-authorize
允许基于角色或权限授权用户
Requires
- laravel/framework: ~5.4
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。
安装
-
在控制台运行
composer require mnabialek/laravel-authorize 1.2.*
以安装此模块
-
打开
config/app.php
-
注释掉以下行
Illuminate\Auth\AuthServiceProvider::class,
-
添加
Mnabialek\LaravelAuthorize\Providers\Auth::class, Mnabialek\LaravelAuthorize\Providers\Authorize::class,
在相同的部分(
providers
)中
-
在控制台运行
php artisan vendor:publish --provider="Mnabialek\LaravelAuthorize\Providers\Authorize"
在您的控制台中发布默认配置文件、中间件、基础策略类和未授权视图
-
在
app/Http/Kernel.php
的$routeMiddleware
中添加'authorize' => \App\Http\Middleware\Authorize::class,
以注册
Authorize
中间件 -
打开
App\Http\Middleware\Authorize.php
并根据您的需求调整errorResponse
和reportUnauthorizedAttempt
。如果默认值符合您的需求,请打开resources/views/errors/401.blade.php
并根据您的需求调整此模板 - 默认情况下,如果用户没有给定路由的权限,将使用此视图。 -
打开您的
User.php
模型文件use Mnabialek\LaravelAuthorize\Contracts\Roleable as RoleableContract;
在类定义之前添加
implements ..., RoleableContract
使
User
类实现此接口,因此它应该看起来像这样 -
作为
...
您应该保留此User
类实现的全部默认接口。use \Mnabialek\LaravelAuthorize\Traits\Roleable;
确保您的
User
类实现了Roleable
接口。为了做到这一点,您需要实现2个方法:hasRole
和getRoles
。为了简化,您可以使用默认的Roleable
特性。只需在您的User
类中放入public function getRoles() { return $this->role ? [$this->role->slug]: []; }
请注意,此特性假定您为
User
模型有role
属性(这意味着您在数据库的users
表中有role
列,该列存储您的角色名称)。在许多情况下,这不会成立,因此您需要至少覆盖getRoles
方法以获取有效的用户角色。假设您有一个一对一的role
关系(用户只分配给单个角色),自定义实现可能如下所示
启动
此模块允许您使用 authorize
中间件来保护您的路由。您有两种方法可以使用此中间件(您可以在同一应用程序中使用这两种方法) - 基于角色或基于权限。
使用此模块,您可以同时为授权用户和非授权用户设置权限,以保持授权层的一致性。
1. 基于角色的授权
您可以指定带有参数的中间件,例如 authorize:manager,employee
- 在这种情况下,只有用户角色会被验证。在这个例子中,如果用户具有任何角色 manager
或 employee
,他们将被允许访问路由,否则他们不会被允许这样做。然而,在上面的例子中,具有 super_roles
的用户也会被允许这样做(super_roles
在 config/authorize.php
中)。所以如果您在 super_roles
中也定义了 admin
,那么具有 admin
角色的用户也将被允许访问此路由,因此如果您指定了其他角色,您就不需要指定 admin
角色了(但当然,如果您想这么做也可以)。
使用此模式不需要进行更多配置。
2. 基于权限的授权
在此选项中,您不能在由 authorize
中间件保护的路由中使用闭包。确保您在这些路由中不要使用它们,否则在应用 authorize
中间件时您将遇到异常。
如果您使用不带任何参数的中间件,例如 authorize
,它将利用 Laravel 授权 并对此机制进行一些额外更改。默认情况下,Laravel 建议为模型创建策略,但在某些情况下,使用控制器的策略可能更合理,这正是本模块所做的事情。
配置
打开 config/authorize.php
文件,并在 super_roles
中放置允许执行任何操作的角色的名称,这样就不需要进行额外的检查。在大多数情况下,将 admin
角色放在这里是合理的,但在某些情况下,如果您想运行详细规则模式,您可能希望将其留空。将您在应用程序中使用的所有角色都放入 permissions
部分的 roles
部分。
保护您的控制器
假设我们有一个名为 UserController
的控制器,它具有默认的 REST 操作 - index
、show
、create
、store
、edit
、update
、destroy
,并且我们希望使用 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
,在我们的控制器中我们有以下方法:index
、show
、create
、store
、edit
、update
、destroy
,所以我们的权限默认看起来应该是这样的
'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; }
定制
默认情况下,所有create
和edit
能力都将自动替换为store
和update
,因为在大多数情况下这将是所需的行为。然而,如果你不想这样使用它,或者你想创建自定义能力映射,只需打开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 许可证。