PHP 怎么PHP 细粒度权限

wen PHP项目 1

本文目录导读:

PHP 怎么PHP 细粒度权限

  1. 基于位运算(Bitwise)—— 最简单的细粒度
  2. 基于 ACL(访问控制列表)—— 通用细粒度
  3. 基于 RBAC + 权限点(最常用)
  4. 基于 ABAC(属性级权限)—— 最强大、最复杂
  5. 使用 Casbin —— 生产级方案
  6. 总结建议

在 PHP 中实现细粒度权限(Fine-Grained Access Control),核心思路是不依赖固定的角色(如 admin/user),而是基于具体的“资源”和“操作”进行判断

常见的实现方式有以下几种,按复杂度和适用场景排序:


基于位运算(Bitwise)—— 最简单的细粒度

适合权限数量极少(≤ 32/64 种)且固定不变的场景(如:增、删、改、查、导出)。

// 定义权限常量(2的n次幂)
define('PERM_VIEW',   1); // 0001
define('PERM_EDIT',   2); // 0010
define('PERM_DELETE', 4); // 0100
define('PERM_EXPORT', 8); // 1000
// 用户权限值(7 = 查看 + 编辑 + 删除)
$userPerm = 7; // 0111
// 检查是否有“删除”权限
if ($userPerm & PERM_DELETE) {
    echo "可以删除";
}

优点:性能极高,数据库字段用一个 int 存储全部权限。
缺点:权限数量受限,无法动态扩展,不支持“某个部门的文档”这种属性级权限。


基于 ACL(访问控制列表)—— 通用细粒度

适合权限数较多、持续变化的场景,每个用户或角色直接关联一个权限列表。

数据库设计示例

-- 权限表
CREATE TABLE permissions (
    id INT PRIMARY KEY,
    name VARCHAR(50),          -- 'article.create'
    description VARCHAR(255)
);
-- 用户-权限关联表
CREATE TABLE user_permissions (
    user_id INT,
    permission_id INT,
    resource_id INT NULL,      -- 可选:针对特定资源,NULL表示所有资源
    PRIMARY KEY (user_id, permission_id, resource_id)
);

PHP 检查逻辑

function checkPermission($userId, $permName, $resourceId = null) {
    $sql = "SELECT 1 FROM user_permissions up
            JOIN permissions p ON up.permission_id = p.id
            WHERE up.user_id = ? AND p.name = ?
            AND (up.resource_id = ? OR up.resource_id IS NULL)";
    // 执行查询,返回 boolean
}

优点:灵活,可控制到每个具体资源(如只允许编辑某篇特定的文章)。
缺点:用户数量多时,数据量爆炸,管理困难。


基于 RBAC + 权限点(最常用)

适合大多数 Web 系统,结合角色解决用户数量大的问题,同时保留细粒度。

核心思想:角色包含权限,用户绑定角色,但支持针对某个用户额外添加/删除特定权限点

数据库结构

-- 权限点(最细粒度)
permissions: id, code('article.edit'), name
-- 角色
roles: id, name
-- 角色-权限关联
role_permissions: role_id, permission_id
-- 用户-角色关联
user_roles: user_id, role_id
-- 用户额外权限(覆盖角色)
user_extra_permissions: user_id, permission_id, type('allow'/'deny')

判断逻辑

function canUser($userId, $permCode, $resourceContext = []) {
    // 1. 查用户所在角色的权限集合
    // 2. 查用户额外权限(deny优先于allow)
    // 3. 合并后判断
    // 4. 可加入自定义回调处理动态逻辑(如“只允许编辑自己创建的文章”)
}

提示:这种结构需要配合缓存(如 Redis 存储用户权限集合),否则每次判断都查库会很慢。


基于 ABAC(属性级权限)—— 最强大、最复杂

适合极度复杂的业务规则(如:财务总监可以审批金额 < 5000 的报销单,但金额 ≥ 5000 需总经理审批)。

核心概念:权限判断 = 用户属性 + 资源属性 + 环境属性(时间、IP…) + 操作

实现示例(伪代码)

function checkAccess($user, $resource, $action) {
    // 规则引擎检查:
    // if $user->role == '财务总监' 
    // AND $action == 'approve' 
    // AND $resource->amount < 5000 
    // THEN allow
}

常见实现方式

  • 自己写规则引擎(if-else / 表达式解析)
  • 使用第三方包:如 php-casbin(推荐),支持 ACL/RBAC/ABAC 多种模型。

使用 Casbin —— 生产级方案

PHP-Casbin 是一个成熟的开源权限库,支持多种模型。

模型文件示例(RBAC + 资源控制)

[request_definition]
r = sub, obj, act
[policy_definition]
p = sub, obj, act
[role_definition]
g = _, _
[matchers]
m = g(r.sub, p.sub) && keyMatch2(r.obj, p.obj) && regexMatch(r.act, p.act)

使用方式

$e = new Enforcer('path/to/model.conf', 'path/to/policy.csv');
if ($e->enforce('alice', '/data/article/123', 'edit')) {
    // 允许操作
}

总结建议

场景 推荐方案
权限很少且固定( ≤ 32 种) 位运算
简单系统,用户少 ACL
中大型系统,标准 Web 应用 RBAC + 权限点
复杂规则(多条件、动态) ABAC / Casbin
不想自己写 Casbin 或使用框架自带(Laravel/ThinkPHP 的 Gate/Policy)

最后提醒:权限检查一定在服务端后端做,前端隐藏按钮只是辅助体验,不可作为安全保障。

抱歉,评论功能暂时关闭!