tatter / permits
CodeIgniter 4的模型权限处理
资助包维护!
tattersoftware
paypal.me/tatter
Requires
- php: ^7.4 || ^8.0
- codeigniter4/authentication-implementation: ^1.0
- tatter/users: ^1.2
Requires (Dev)
- codeigniter4/devkit: ^1.0
- codeigniter4/framework: ^4.1
- tatter/imposter: ^1.1
This package is auto-updated.
Last update: 2024-09-17 21:36:13 UTC
README
CodeIgniter 4的模型权限处理
快速开始
- 使用Composer安装:
> composer require tatter/permits
- 将特性添加到你的模型中
class BlogModel extends Model { use PermitsTrait;
- 使用CRUDL动词检查访问权限:
if ($blogs->mayCreate()) ...
特性
Permits
解决了对象权限管理中的常见问题:"此用户能否添加/更改/删除此项目?" 此库通过添加CRUDL风格的动词到你的模型类,为你的模型类提供了对象级别的访问权限。
安装
通过Composer轻松安装以利用CodeIgniter 4的自动加载功能,并始终保持最新状态
composer require tatter/permits
或者,通过下载源文件并将目录添加到app/Config/Autoload.php
来手动安装。
Permits
需要Composer提供codeigniter4/authentication-implementation
,如CodeIgniter身份验证指南中所述。你必须安装并配置一个支持的包,以便Permits
能够了解你的用户。
配置(可选)
可以通过扩展其配置文件来改变库的默认行为。将**examples/Permits.php复制到app/Config/
,并遵循注释中的说明。如果没有在app/Config
中找到配置文件,库将使用其自身的。
配置文件包括一组$default
访问级别,你可以修改你自己的版本。你打算使用的每个模型都应该有一个与它的$table
属性对应的Config属性,其中包含需要从默认值调整的属性。
配置完成后,只需在模型中包含PermitsTrait
即可启用这些方法
use CodeIgniter\Model; use Tatter\Permits\Traits\PermitsTrait; class FruitModel extends Model { use PermitsTrait; ...
用法
有两种类型的权限:显式和推断。两者都依赖于这个常见的CRUDL动词集合
- 创建:创建新项目
- 读取:查看单个项目
- 更新:更改单个项目
- 删除:删除单个项目
- 列表:查看所有项目的索引
- 管理员:无论其他权限如何,都可以执行上述任何操作
使用相应的模型动词来检查访问权限
if (! $model->mayCreate()) { return redirect()->back()->with('error', 'You do not have permission to do that!'); } $item = $model->find($id); if (! $model->mayUpdate($item)) { return redirect()->back()->with('error', 'You can only update your own items!'); }
PermitsTrait
将根据当前登录用户(如果有的话)检查访问权限,但你也可以传递一个明确的用户ID来检查
if (! $model->mayAdmin($userId)) { log_message('debug', "User #{$userId} attempted to access item administration."); }
显式
显式权限通过你的授权库授予用户或组。 Permits
使用Tatter\Users与用户记录交互并确定显式权限。如果你的认证包不支持Users
自动发现,请确保阅读文档。
在检查显式权限时,Permits
使用"table.verb"格式。例如,如果你的项目包含一个BlogModel
,你希望允许博客编辑员编辑任何人的博客条目,你将"blogs.edit"分配给"editors"组。
注意:显式权限始终优先于推断权限。
推断
推断权限使用配置(见上文)来确定任何单个用户对项目或项目组的访问权限。可以应用于每个动词的有四种访问级别(这些是 Tatter\Permits\Config\Permits
上的常量)
NOBODY
:禁止所有访问,除非有明确的权限OWNERS
:需要经过验证的用户拥有该物品OWNERS
:需要经过验证的用户拥有该物品USERS
:需要任何经过验证的用户ANYBODY
:允许任何人,无论是否经过验证或拥有
除了访问级别之外,每个模型都应该配置如何确定物品所有权。在您表的单个属性Config上设置所需的以下值
userKey
:在物品或其连接表中用户ID的字段pivotKey
:在连接表中物品ID的字段pivotTable
:将物品与所有者连接的表
示例
您的Web应用程序包含一个内容管理系统,允许站点所有者登录并更新网站的各个部分。这包括一个博客部分,它有自己的模型、控制器和视图。任何访问您网站的访客都可以创建账户并提交博客条目,但必须在“上线”前进行审批。作为您这样优秀的开发者,您决定使用 Tatter\Permits
来管理博客条目的访问权限。
首先,我们需要确保我们的认证包已经准备好并设置了正确的权限。这可能会因包而异,但 Shield
使用 配置文件 定义组和权限。我们将保留现有的组并添加一个新的“编辑者”组。 app/Config/AuthGroups.php
public $groups = [ 'superadmin' => [ 'title' => 'Super Admin', 'description' => 'Complete control of the site.', ], 'admin' => [ 'title' => 'Admin', 'description' => 'Day to day administrators of the site.', ], 'developer' => [ 'title' => 'Developer', 'description' => 'Site programmers.', ], 'user' => [ 'title' => 'User', 'description' => 'General users of the site. Often customers.', ], 'beta' => [ 'title' => 'Beta User', 'description' => 'Has access to beta-level features.', ], 'editor' => [ 'title' => 'Blog Editors', 'description' => 'Has access to all blog entries.', ], ];
我们想给一些组明确的博客管理权限,所以在同一个文件中,我们添加了一个新的以格式"{table}.{verb}"的权限
public $permissions = [ 'admin.access' => 'Can access the sites admin area', 'admin.settings' => 'Can access the main site settings', 'users.manage-admins' => 'Can manage other admins', 'users.create' => 'Can create new non-admin users', 'users.edit' => 'Can edit existing non-admin users', 'users.delete' => 'Can delete existing non-admin users', 'beta.access' => 'Can access beta-level features', 'blogs.admin' => 'Allows all access to blog model operations', ];
最后,我们将在同一个文件中添加新的权限到我们想要添加权限的组中
public $matrix = [ 'superadmin' => [ 'admin.*', 'users.*', 'beta.*', 'blogs.*', ], 'admin' => [ 'admin.access', 'users.create', 'users.edit', 'users.delete', 'beta.access', 'blogs.admin', ], 'developer' => [ 'admin.access', 'admin.settings', 'users.create', 'users.edit', 'beta.access', ], 'user' => [], 'beta' => [ 'beta.access', ], 'editor' => [ 'blogs.admin', ], ];
这就是第三方授权配置的全部内容!接下来是 Permits
- 我们首先需要在Config文件中设置权限。我们可以保留默认设置,并添加自己的属性。 app/Config/Permits.php
/* * @var array<string,mixed> */ public $blogs = [ 'admin' => self::NOBODY, 'create' => self::USERS, 'list' => self::USERS, 'read' => self::OWNERS, 'update' => self::OWNERS, 'delete' => self::OWNERS, 'userKey' => 'user_id', 'pivotKey' => null, 'pivotTable' => null, ]; }
让我们分解一下。
-
第一个权限,“admin”:我们在上面的认证包中已经赋予了明确的权利,因此我们不希望其他人有权访问,所以是
NOBODY
。明确的权限具有优先级,所以我们的“superadmin”、“admin”和“editor”组仍然可以完全访问。 -
接下来是“list”和“create”:两者都可供
USERS
- 即,任何登录的用户使用。他们将能够创建新的条目并查看其他人的条目列表。 -
然而,“read”、“update”和“delete”都限制为
OWNERS
- 即,经过验证的用户只能点击他们自己的条目来阅读和修改内容。 -
最后,我们需要一种让
Permits
来决定“这是谁的所有权”的方法。在这种情况下,我们设置了“userKey”,但留空了连接属性 - 这意味着,我们的blogs
表有一个名为user_id
的字段,该字段与创建博客的用户ID相对应。
在更复杂的设置中,如果多个用户被分配到多个博客,我们可能有一个连接表,在这种情况下,我们也会将“pivotTable”设置为类似
blogs_users
的值,并将“pivotKey”设置为类似blog_id
的值。
配置完成!集成最后一部分是向博客模型添加我们的特质,这将处理激活我们的访问动词。 app/Models/BlogModel.php
use App\Entities\Blog; use CodeIgniter\Model; use Tatter\Permits\Traits\PermitsTrait; class BlogModel extends Model { use PermitsTrait; protected $table = 'blogs'; protected $primaryKey = 'id'; protected $returnType = Blog::class; ... }
集成完成!现在您可以开始在使用代码中使用 Permits
。让我们为我们的博客创建一个控制器,并在常规代码之前添加一些权限检查。app/Controllers/Blogs.php
<?php namespace App\Controllers; use App\Models\BlogModel; use CodeIgniter\HTTP\RedirectResponse; class Blogs extends BaseController { /** * @var BlogModel */ protected $model; /** * Preloads the model. */ public function __construct() { $this->model = model(BlogModel::class); } /** * Displays the list of approved blogs * for all visitors of the website. */ public function index(): string { return view('blogs/public', [ 'blogs' => $this->model->findAll(), ]); } /** * Displays blogs eligible for updating * based on the authenticated user (handled * by our authentication Filter). */ public function manage(): string { // Admin access sees all blogs, otherwise limit to the current user if (! $this->model->mayAdmin()) { $this->model->where('user_id', user_id()); } return view('blogs/manage', [ 'blogs' => $this->model->findAll(), ]); } /** * Shows a single blog with options * to update or delete. * * @return RedirectResponse|string */ public function edit($blogId) { // Verify the blog if (empty($blogId) || null === $blog = $this->model->find($blogId)) { return redirect()->back()->with('error', 'Could not find that blog entry.'); } // Check access if (! $this->model->mayUpdate($blog)) { return redirect()->back()->with('error', 'You do not have permission to do that.'); } return view('blogs/edit', [ 'blog' => $blog, ]); } ...
希望从这里您能理解!对于喜欢使控制器更轻量级的开发者,您甚至可以将这些检查中的某些放入过滤器中。
扩展
CRUDL风格的函数只是一个起点!您的模型可以覆盖这些内置函数或添加新的函数,这些函数可以利用库的结构和方法。查看源代码库中的代码以获取如何利用显式和隐式权限的灵感。