mstfkhazaal / 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.13.0
- v0.12.0
- v0.11.0
- v0.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-patch-1
- dev-dependabot/composer/guzzlehttp/psr7-2.2.1
- dev-laravel-6.0
- dev-analysis-8mK1LV
- dev-develop
- dev-feature-add-commands
This package is auto-updated.
Last update: 2024-09-30 01:20:04 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. 用户类
在您的用户类中,添加 trait 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+,则可以使用 Middleware 参数。
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 的 Defender 扩展用于使用 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)
:
通过角色 ID roleId
在数据库中查找角色。
Defender::findPermission($permissionName)
:
通过名称 $permissionName
在数据库中查找权限。
Defender::findPermissionById($permissionId)
:
通过 ID $permissionId
在数据库中查找权限。
Defender::createRole($roleName)
:
在数据库中创建新的角色。
Defender::createPermission($permissionName)
:
在数据库中创建新的权限。
Defender::is($roleName)
:
检查当前用户是否属于该角色。
Defender::javascript()->render()
:
返回一个 JavaScript 脚本,其中包含当前用户的所有角色和权限列表。变量名称可以修改。
使用特性
要添加 Defender 的功能,需要在您的 User 模型中添加特性 HasDefender
(通常是 App\User
)。
<?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 驱动程序实现角色和权限模型的两个示例。
<?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; }
您必须使用正确的特性,并且每个类都必须实现相应的接口合同。