本文目录导读:

在 PHP 中实现“字段权限”通常指控制谁能访问或修改数据表的某个字段(普通用户不能查看 salary 字段,管理员才能编辑 is_admin 字段)。
下面是几种常见的实现方案,从简单到专业:
基础方案:角色判断 + 逻辑过滤(最常用)
在查询数据库后,根据用户角色对结果数组进行字段过滤。
<?php
function filterFieldsByRole(array $data, string $role): array
{
// 定义不同角色的可见字段
$fieldPermissions = [
'admin' => ['id', 'name', 'email', 'salary', 'phone'],
'user' => ['id', 'name', 'email'],
'guest' => ['id', 'name'],
];
$allowedFields = $fieldPermissions[$role] ?? []; // 默认为空
// 只保留允许的字段
return array_intersect_key($data, array_flip($allowedFields));
}
// 使用示例:
$userData = [
'id' => 1,
'name' => 'Alice',
'email' => 'alice@example.com',
'salary' => 50000,
'phone' => '1234567890'
];
$currentUserRole = 'user';
$filteredData = filterFieldsByRole($userData, $currentUserRole);
print_r($filteredData);
// 输出:Array ( [id] => 1 [name] => Alice [email] => alice@example.com )
优点:简单直接,适合中小项目。
缺点:硬编码权限,数据库返回大字段集再过滤,效率略低。
数据库层:查询时动态选择字段
更适合高性能要求(只查询需要的字段,减少网络传输)。
<?php
function getUserFieldsByRole(string $role): array
{
$fieldMap = [
'admin' => ['id', 'name', 'email', 'salary'],
'user' => ['id', 'name', 'email'],
'guest' => ['id', 'name'],
];
return $fieldMap[$role] ?? ['id']; // 兜底至少返回 id
}
// 构建查询
$role = 'user';
$fields = getUserFieldsByRole($role);
$fieldStr = implode(', ', $fields);
$query = "SELECT {$fieldStr} FROM users WHERE id = ?";
// 然后使用 PDO 执行 $query...
优点:数据库只返回可见字段,减少 I/O。
缺点:仍依赖硬编码;复杂权限(如字段级读写分离)需要更细粒度控制。
通用方案:权限配置 + 中间件(推荐)
将权限定义放在配置文件中,结合一个拦截器统一处理。
1 权限配置文件 permissions.php
return [
'User' => [ // 模型或资源名
'fields' => [
'salary' => ['admin', 'hr'], // 只有 admin 和 hr 可见
'phone' => ['admin'],
'email' => ['admin', 'user', 'hr'],
'*'=> ['admin', 'user', 'hr', 'guest'] // 默认所有角色可见
]
]
];
2 权限检查类
<?php
class FieldPermission
{
private array $config;
private string $userRole;
public function __construct(array $config, string $userRole)
{
$this->config = $config;
$this->userRole = $userRole;
}
public function filter(string $resource, array $data): array
{
$fieldsConfig = $this->config[$resource]['fields'] ?? [];
$result = [];
foreach ($data as $field => $value) {
if ($this->isFieldAllowed($field, $fieldsConfig)) {
$result[$field] = $value;
}
}
return $result;
}
private function isFieldAllowed(string $field, array $fieldConfig): bool
{
// 如果有该字段的特定权限
if (isset($fieldConfig[$field])) {
return in_array($this->userRole, $fieldConfig[$field]);
}
// 否则使用默认权限(*)
$default = $fieldConfig['*'] ?? ['*']; // *表示所有角色
return in_array($this->userRole, $default) || in_array('*', $default);
}
}
3 使用
$config = require 'permissions.php';
$checker = new FieldPermission($config, 'user');
$safeData = $checker->filter('User', $userData);
优点:配置与逻辑分离,易维护,支持任意角色。
缺点:需要额外加载配置和处理。
框架级方案(以 Laravel 为例)
Laravel 可以使用 Policy(策略) + Resource(API 资源) 实现字段权限。
1 创建 Policy
php artisan make:policy UserPolicy --model=User
2 在 Policy 中定义 visibleFields
public function visibleFields(User $user) : array
{
if ($user->isAdmin()) {
return ['*']; // 全部可见
}
return ['id', 'name', 'email'];
}
3 使用 API Resource 过滤
class UserResource extends JsonResource
{
public function toArray($request)
{
$allowed = $request->user()->can('visibleFields', $this->resource)
? $this->resource->toArray()
: array_intersect_key(
$this->resource->toArray(),
array_flip(['id', 'name', 'email'])
);
return $allowed;
}
}
优点:深度集成框架,支持依赖注入、缓存等。
缺点:学习成本较高。
终极方案:读写分离权限(复杂场景)
如果需要不同的字段在读取和修改时有不同权限:
| 字段 | 读权限 | 写权限 |
|---|---|---|
| salary | admin, hr | admin |
| phone | admin | admin, user |
| admin, user | admin, user, hr |
可扩展上面的方案为:
$permissions = [
'User' => [
'salary' => ['read' => ['admin','hr'], 'write' => ['admin']],
'phone' => ['read' => ['admin'], 'write' => ['admin','user']],
'email' => ['read' => ['admin','user'], 'write' => ['admin','user','hr']],
'*' => ['read' => ['*'], 'write' => ['*']],
]
];
然后检查时需提供操作类型 $operation = 'read' 或 'write'。
总结对比
| 方案 | 复杂度 | 灵活性 | 推荐场景 |
|---|---|---|---|
| 角色 + 逻辑过滤 | ⭐低 | ⭐低 | 简单、快速原型 |
| 数据库层动态选字段 | ⭐中 | ⭐中 | 性能敏感、接口统一 |
| 配置化中间件 | ⭐⭐中 | ⭐⭐高 | 中型项目,需快速调整权限 |
| 框架集成 (Laravel等) | ⭐⭐⭐高 | ⭐⭐⭐高 | 大型项目,团队规范 |
| 读写分离权限 | ⭐⭐⭐高 | ⭐⭐⭐高 | 复杂业务(金融、人事系统) |
建议:从方案3(配置化中间件)开始,它兼顾扩展性和开发效率,未来升级到框架集成也很容易。