artesaos / defender
Laravel 的角色和权限
Requires
- php: >=7.2.0 || ^8.0
- laravel/framework: ^6.0 || ^7.0 || ^8.0 || ^9.0
- phpspec/phpspec: ^6.3 || ^7.0
Requires (Dev)
- fakerphp/faker: ^1.0
- friendsofphp/php-cs-fixer: ~2.11
- orchestra/database: ^4.0 || ^5.0 || ^6.0 || ^7.0
- orchestra/testbench: ^4.0 || ^5.0 || ^6.0 || ^7.0
- phpunit/phpunit: ^8.0 || ^9.0
- dev-master
- 5.x-dev
- v1.x-dev
- v0.12.0
- v0.11.0
- 0.10.0
- v0.9.0
- 0.8.x-dev
- v0.8.3
- v0.8.2
- v0.8.1
- v0.8.0
- 0.7.x-dev
- 0.7
- 0.6.2
- 0.6.1
- 0.6
- 0.5
- v0.4.6
- v0.4.5
- v0.4.4
- v0.4.3
- v0.4.2
- v0.4.1
- v0.3.1
- v0.3.0
- v0.2.16
- v0.2.15
- v0.2.14
- v0.2.13
- v0.2.12
- v0.2.11
- v0.2.10
- v0.2.9
- v0.2.8
- v0.2.7
- v0.2.6
- v0.2.5
- v0.2.4
- v0.2.3
- v0.2.2
- v0.2.1
- v0.2.0-alpha
- v0.1.0-alpha
- dev-dependabot/composer/guzzlehttp/psr7-2.5.0
- dev-dependabot/composer/symfony/http-kernel-5.4.20
- dev-laravel-6.0
- dev-analysis-8mK1LV
- dev-develop
- dev-feature-add-commands
This package is auto-updated.
Last update: 2024-09-21 23:19:40 UTC
README
Defender 是 Laravel 5 / 6 / 7 / 8 / 9 (单认证) 的访问控制列表 (ACL) 解决方案。 (不兼容多认证)
考虑到安全和易用性,本项目旨在为您提供一个安全的方式来控制应用程序访问,同时不失编码的乐趣。
当前构建状态
统计数据
欢迎贡献
Defender 正在寻找维护者和贡献者。
安装
1. 依赖关系
使用 composer,执行以下命令以自动更新您的 composer.json
,使用相应的包版本
composer require artesaos/defender
或者手动更新您的 composer.json
文件
{ "require": { "artesaos/defender": "~0.10.0" } }
2. 提供者
如果您使用 Laravel >= 5.5,则可以跳过此部分,因为我们的包支持自动发现。
您需要更新应用程序配置以注册包,使其可以被 Laravel 加载。只需更新您的 config/app.php
文件,在 'providers'
节的末尾添加以下代码
// file START ommited 'providers' => [ // other providers ommited \Artesaos\Defender\Providers\DefenderServiceProvider::class, ], // file END ommited
3. 用户类
在您的用户类中,添加特质 Artesaos\Defender\Traits\HasDefender
以启用权限和角色的创建
<?php namespace App; use Illuminate\Auth\Authenticatable; use Illuminate\Database\Eloquent\Model; use Artesaos\Defender\Traits\HasDefender; use Illuminate\Auth\Passwords\CanResetPassword; use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract; use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract; class User extends Model implements AuthenticatableContract, CanResetPasswordContract { use Authenticatable, CanResetPassword, HasDefender; ...
如果您使用 laravel 5.2+,这里有一些小的不同
<?php namespace App; use Artesaos\Defender\Traits\HasDefender; use Illuminate\Foundation\Auth\User as Authenticatable; class User extends Authenticatable { use HasDefender; ...
4. 发布配置文件和迁移
要发布默认配置文件和数据库迁移,请执行以下命令
php artisan vendor:publish
执行迁移,以便在您的数据库中创建表
php artisan migrate
您也可以只发布配置文件或迁移
php artisan vendor:publish --tag=config
或者
php artisan vendor:publish --tag=migrations
如果您已经发布了 defender 文件,但出于某种原因想要覆盖之前发布的文件,请添加 --force
标志。
5. Facade(可选)
为了使用 Defender
facade,您需要在 config/app.php
文件中注册它,您可以这样做
// config.php file // file START ommited 'aliases' => [ // other Facades ommited 'Defender' => \Artesaos\Defender\Facades\Defender::class, ], // file END ommited
6. Defender 中间件(可选)
如果您必须控制 Defender 提供的访问,Defender 提供中间件来保护您的路由。如果您必须通过 Laravel 路由控制访问,Defender 为一些简单任务提供了内置中间件。要使用它们,只需将它们放在您的 app/Http/Kernel.php
文件中。
protected $routeMiddleware = [ 'auth' => \App\Http\Middleware\Authenticate::class, 'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class, 'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class, // Access control using permissions 'needsPermission' => \Artesaos\Defender\Middlewares\NeedsPermissionMiddleware::class, // Simpler access control, uses only the groups 'needsRole' => \Artesaos\Defender\Middlewares\NeedsRoleMiddleware::class ];
下面将介绍如何使用中间件。
6.1 - 创建自己的中间件
如果内置中间件不符合您的需求,您可以使用 Defender 的 API 来控制访问。
用法
Defender 仅处理访问控制。认证仍由 Laravel 的 Auth
执行。
注意:如果您使用不同的用户模型或已更改命名空间,请更新您的 defender 配置文件中的 user_model 键。
创建角色和权限
使用命令
您可以使用这些命令为您应用程序创建角色和权限。
php artisan defender:make:role admin # creates the role admin php artisan defender:make:role admin --user=1 # creates the role admin and attaches this role to the user where id=1 php artisan defender:make:permission users.index "List all the users" # creates the permission php artisan defender:make:permission users.create "Create user" --user=1 # creates the permission and attaches it to user where id=1 php artisan defender:make:permission users.destroy "Delete user" --role=admin # creates the permission and attaches it to the role admin
使用 seeder 或 artisan tinker
您还可以使用 Defender 的 API。您可以创建一个 Laravel Seeder 或使用 php artisan tinker
。
use App\User; $roleAdmin = Defender::createRole('admin'); // The first parameter is the permission name // The second is the "friendly" version of the name. (usually for you to show it in your application). $permission = Defender::createPermission('user.create', 'Create Users'); // You can assign permission directly to a user. $user = User::find(1); $user->attachPermission($permission); // or you can add the user to a group and that group has the power to rule create users. $roleAdmin->attachPermission($permission); // Now this user is in the Administrators group. $user->attachRole($roleAdmin);
使用中间件
要保护您的路由,您可以使用内置中间件。
Defender 需要 Laravel 的 Auth,因此,在您打算使用的 Defender 中间件之前,请使用
auth
中间件。
检查权限:needsPermissionMiddleware
Route::get('foo', ['middleware' => ['auth', 'needsPermission'], 'shield' => 'user.create', function() { return 'Yes I can!'; }]);
如果您使用的是Laravel 5.1及以上版本,则可以使用中间件参数。
Route::get('foo', ['middleware' => ['auth', 'needsPermission:user.index'], function() { return 'Yes I can!'; }]);
使用这种语法,您也可以在控制器中使用中间件。
$this->middleware('needsPermission:user.index');
您可以传递一个数组,用于检查权限。
Route::get('foo', ['middleware' => ['auth', 'needsPermission'], 'shield' => ['user.index', 'user.create'], function() { return 'Yes I can!'; }]);
当使用中间件参数时,使用|
分隔多个权限。
Route::get('foo', ['middleware' => ['auth', 'needsPermission:user.index|user.create'], function() { return 'Yes I can!'; }]);
或者,在控制器中
$this->middleware('needsPermission:user.index|user.create');
当您传递一个权限数组时,只有当用户拥有所有权限时,路由才会被触发。但是,如果您想允许用户至少拥有一个权限时访问路由,只需添加'any' => true
。
Route::get('foo', ['middleware' => ['auth', 'needsPermission'], 'shield' => ['user.index', 'user.create'], 'any' => true, function() { return 'Yes I can!'; }]);
或者,使用中间件参数,将其作为第二个参数传递
Route::get('foo', ['middleware' => ['auth', 'needsPermission:user.index|user.create,true'], function() { return 'Yes I can!'; }]);
或者,在控制器中
$this->middleware('needsPermission:user.index|user.create,true');
检查角色:needsRoleMiddleware
这与之前的中间件类似,但只检查角色,这意味着它不检查权限。
Route::get('foo', ['middleware' => ['auth', 'needsRole'], 'is' => 'admin', function() { return 'Yes I am!'; }]);
如果您使用的是Laravel 5.1,则可以使用中间件参数。
Route::get('foo', ['middleware' => ['auth', 'needsRole:admin'], function() { return 'Yes I am!'; }]);
使用这种语法,您也可以在控制器中使用中间件。
$this->middleware('needsRole:admin');
您可以传递一个数组,用于检查权限。
Route::get('foo', ['middleware' => ['auth', 'needsRole'], 'shield' => ['admin', 'member'], function() { return 'Yes I am!'; }]);
当使用中间件参数时,使用|
分隔多个角色。
Route::get('foo', ['middleware' => ['auth', 'needsRole:admin|editor'], function() { return 'Yes I am!'; }]);
或者,在控制器中
$this->middleware('needsRole:admin|editor');
当您传递一个权限数组时,只有当用户拥有所有权限时,路由才会被触发。但是,如果您想允许用户至少拥有一个权限时访问路由,只需添加'any' => true
。
Route::get('foo', ['middleware' => ['auth', 'needsRole'], 'is' => ['admin', 'member'], 'any' => true, function() { return 'Yes I am!'; }]);
或者,使用中间件参数,将其作为第二个参数传递
Route::get('foo', ['middleware' => ['auth', 'needsRole:admin|editor,true'], function() { return 'Yes I am!'; }]);
或者,在控制器中
$this->middleware('needsRole:admin|editor,true');
在视图中使用
Laravel的Blade扩展用于使用Defender。
@shield
@shield('user.index')
shows your protected stuff
@endshield
@shield('user.index')
shows your protected stuff
@else
shows the data for those who doesn't have the user.index permission
@endshield
您还可以使用通配符(*)
@shield('user.*')
shows your protected stuff
@else
shows the data for those who doesn't have the any permission with 'user' prefix
@endshield
@is
@is('admin')
Shows data for the logged user and that belongs to the admin role
@endis
@is('admin')
Shows data for the logged user and that belongs to the admin role
@else
shows the data for those who doesn't have the admin permission
@endis
@is(['role1', 'role2'])
Shows data for the logged user and that belongs to the admin role
@else
shows the data for those who doesn't have the admin permission
@endis
使用JavaScript辅助工具
该扩展提供辅助工具,以便您可以在前端与用户权限进行交互。
echo Defender::javascript()->render(); // or echo app('defender')->javascript()->render(); // or echo app('defender.javascript')->render();
此辅助工具注入一段JavaScript代码,包含当前用户的全部权限和角色。
使用外观
使用Defender的外观,您可以在应用的任何部分访问API并使用它。
Defender::hasPermission($permission)
:
检查登录用户是否有$permission
。
Defender::canDo($permission)
:
检查登录用户是否有$permission
。如果角色是superuser
,则返回true
Defender::roleHasPermission($permission)
:
检查登录用户是否有$permission
,仅检查角色权限。
Defender::hasRole($roleName)
:
检查登录用户是否属于角色$roleName
。
Defender::roleExists($roleName)
:
检查角色$roleName
是否存在于数据库中。
Defender::permissionExists($permissionName)
:
检查权限$permissionName
是否存在于数据库中。
Defender::findRole($roleName)
:
通过名称$roleName
在数据库中查找角色。
Defender::findRoleById($roleId)
:
通过角色IDroleId
在数据库中查找角色。
Defender::findPermission($permissionName)
:
通过名称$permissionName
在数据库中查找权限。
Defender::findPermissionById($permissionId)
:
通过ID$permissionId
在数据库中查找权限。
Defender::createRole($roleName)
:
在数据库中创建一个新的角色。
Defender::createPermission($permissionName)
:
在数据库中创建一个新的权限。
Defender::is($roleName)
:
检查当前用户是否属于该角色。
Defender::javascript()->render()
:
返回一个JavaScript脚本,包含当前用户的所有角色和权限列表。变量名可以修改。
使用特性
为了添加Defender的特性,您需要在您的用户模型(通常是App\User
)中添加特性HasDefender
。
<?php namespace App; // Declaration of other omitted namespaces use Artesaos\Defender\Traits\HasDefender; class User extends Model implements AuthenticatableContract, CanResetPasswordContract { use Authenticatable, CanResetPassword, HasDefender; // Rest of the class }
除了配置关系之外,此特性还会向您的对象App\User
添加以下方法
public function hasPermission($permission)
:
此方法检查登录用户是否有$permission
权限
在Defender中,有两种权限:用户权限
和角色权限
。默认情况下,用户继承的权限是其所属角色的权限。但是,只要设置了用户权限,它就会优先于角色权限。
public function foo(Authenticable $user) { if ($user->hasPermission('user.create')); }
public function roleHasPermission($permission)
:
此方法与上一个方法类似,唯一的区别是用户权限不考虑,但是,只使用用户所属角色的权限来检查访问权限。
public function foo(Authenticable $user) { if ($user->roleHasPermission('user.create'); }
public function attachRole($role)
:
将用户附加到角色 $role
。变量 $role
可能是类型为 Artesaos\Defender\Role
的对象,或者包含角色 ids
的数组。
public function foo(Authenticable $user) { $role = Defender::findRole('admin'); // Returns an Artesao\Defender\Role $user->attachRole($role); // or $roles = [1, 2, 3]; // Using an array of ids $user->attachRole($roles); }
public function detachRole($role)
:
从用户中移除角色 $role
(与 attachRole()
相反)。
public function foo(Authenticable $user) { $role = Defender::findRole('admin'); // Returns an Artesao\Defender\Role $user->detachRole($role); // ou $roles = [1, 2, 3]; // Using an array of ids $user->detachRole($roles); }
public function syncRoles(array $roles = array())
:
这与 attachRole()
方法类似,但在方法运行后,只有数组 $roles
中的角色将存在于关系中。$roles
是所需角色的 ids
数组。
public function foo(Authenticable $user) { $roles = [1, 2, 3]; // Using an array of ids $user->syncRoles($roles); }
public function attachPermission($permission, array $options = array())
:
将用户附加到权限 $permission
。变量 $permission
是 Artesaos\Defender\Permission
类的实例。
public function foo(Authenticable $user) { $permission = Defender::findPermission('user.create'); $user->attachPermission($permission, [ 'value' => true // true = has the permission, false = doesn't have the permission, ]); }
public function detachPermission($permission)
:
从用户中移除权限 $permission
。变量 $permission
可能是 Artesaos\Defender\Permission
类的实例或包含要移除的权限 ids
的数组。
public function foo(Authenticable $user) { $permission = Defender::findPermission('user.create'); $user->detachPermission($permission); // or $permissions = [1, 3]; $user->detachPermission($permissions); }
public function syncPermissions(array $permissions)
:
这与 syncRoles
方法类似,但在方法运行后,只有数组 $permissions
中的角色将存在于关系中。
public function foo(Authenticable $user) { $permissions = [ 1 => ['value' => false], 2 => ['value' => true, 3 => ['value' => true] ]; $user->syncPermissions($permissions); }
public function revokePermissions()
:
移除所有用户权限。
public function foo(Authenticable $user) { $user->revokePermissions(); }
public function revokeExpiredPermissions()
:
从用户中移除所有临时过期的权限。关于临时权限的更多信息见下文。
public function foo(Authenticable $user) { $user->revokeExpiredPermissions(); }
临时权限
Defender 最酷的功能之一是向组或用户添加临时权限。
例如
用户 John 属于 'admins' 角色,但是我想暂时移除 John 创建新用户的权限。
在这种情况下,我们需要附加一个值为 false
的权限,明确禁止用户执行该操作。由于默认情况下,用户权限继承自其角色的权限,因此您必须添加此权限,并设置值为 false
。当您分配用户权限时,这始终具有优先级。
例如。以下我们撤销用户在 7 天内的 user.create
权限。
public function foo() { $userX = App\User::find(3); $permission = Defender::findPermission('user.create'); $userX->attachPermission($permission, [ 'value' => false, // false means that he will not have the permission, 'expires' => \Carbon\Carbon::now()->addDays(7) // Set the permission's expiration date ]); }
7 天后,用户将再次拥有该权限。
允许用户在一定时间内执行某些操作。
要允许用户在指定时间内临时访问执行特定操作,只需设置 expires
键。默认情况下,value
键将为 true
。
public function foo() { $user = App\User::find(1); $permission = Defender::findPermission('user.create'); $user->attachPermission($permission, [ 'expires' => \Carbon\Carbon::now()->addDays(7) ]; }
还可以扩展现有的临时权限:只需使用 $user->extendPermission($permissionName, array $options)
方法。
使用自定义角色和权限模型
要使用自己的角色和权限模型类,首先在 defender.php
配置文件中设置 role_model
和 permission_model
键。
以下是如何使用 jenssegers/laravel-mongodb 驱动程序实现 MongoDB 中的角色和权限模型的两个示例。
<?php // Role model namespace App; use Jenssegers\Mongodb\Eloquent\Model; use Artesaos\Defender\Traits\Models\Role; use Artesaos\Defender\Contracts\Role as RoleInterface; /** * Class Role. */ class Role extends Model implements RoleInterface { use Role; }
<?php // Permission model namespace App; use Jenssegers\Mongodb\Eloquent\Model; use Artesaos\Defender\Traits\Models\Permission; use Artesaos\Defender\Contracts\Permission as PermissionInterface; /** * Class Permission. */ class Permission extends Model implements PermissionInterface { use Permission; }
您必须使用正确的特性和每个类都必须实现相应的接口合约。