本文目录导读:

在 PHP 中实现“策略管理点”(通常指访问控制策略或业务策略的管理与执行点)通常涉及 设计模式(如策略模式、责任链模式)和 权限/配置管理 的结合。
下面我将从 核心概念、典型实现方式 以及 代码示例 三个维度为你解答。
核心概念:什么是策略管理点?
在系统架构(如 ABAC - 基于属性的访问控制 或 业务规则引擎)中,策略管理点通常指:
- Policy Enforcement Point (PEP):拦截请求,执行策略判断。
- Policy Decision Point (PDP):根据策略规则做出决策(允许/拒绝)。
- Policy Administration Point (PAP):管理策略的存储、编辑、版本控制。
- Policy Information Point (PIP):获取决策所需的属性(如用户角色、时间、IP)。
在 PHP 中,你通常需要将 策略的定义(规则)与 策略的执行(判断逻辑)分离。
主要实现方式
使用 策略模式(Strategy Pattern)+ 策略上下文
适用于逻辑不复杂、策略数量有限且经常切换的场景。
- 策略管理点:由
Context类持有当前生效的策略,并委托给具体策略执行。 - 策略:每个策略是一个独立的类。
<?php
// 1. 策略接口 (抽象策略)
interface AccessStrategy {
public function check(array $attributes): bool;
}
// 2. 具体策略 (具体算法/规则)
class AdminOnlyStrategy implements AccessStrategy {
public function check(array $attributes): bool {
return $attributes['role'] === 'admin';
}
}
class TimeBasedStrategy implements AccessStrategy {
public function check(array $attributes): bool {
$hour = date('H');
return $hour >= 9 && $hour <= 18; // 仅工作时间允许
}
}
// 3. 策略管理点 (Context / 决策引擎)
class AccessDecisionPoint {
private AccessStrategy $strategy;
public function setStrategy(AccessStrategy $strategy): void {
$this->strategy = $strategy;
}
public function decide(string $action, array $userAttributes): bool {
// 这里就是管理点:执行策略判断
return $this->strategy->check($userAttributes);
}
}
// 4. 使用示例
$access = new AccessDecisionPoint();
// 动态设置策略
$access->setStrategy(new AdminOnlyStrategy());
$result = $access->decide('delete_post', ['role' => 'editor']); // false
// 切换策略
$access->setStrategy(new TimeBasedStrategy());
$result2 = $access->decide('login', ['ip' => '192.168.1.1']); // 取决于时间
使用 配置驱动 + 中央策略文件(适合复杂或大量规则)
如果你的策略经常变化(如由非技术人员管理),建议将策略存储在数据库或 YAML/JSON 文件中,运行时解析并执行。
- PDP:一个核心类,读取配置,循环匹配规则。
- PIP:提供用户属性(如角色、部门)。
<?php
// 1. 定义策略存储格式 (例如从数据库或JSON读取)
$policyJson = '[
{"action": "edit_document", "subject_role": "admin", "effect": "allow"},
{"action": "edit_document", "subject_role": "editor", "effect": "allow", "condition": {"owner": true}},
{"action": "delete_document", "subject_role": "admin", "effect": "allow"}
]';
// 2. 策略执行引擎 (PDP)
class PolicyEngine {
private array $policies;
private array $pip;
public function __construct(string $policyJson, array $pip) {
$this->policies = json_decode($policyJson, true);
$this->pip = $pip; // 属性信息点
}
// 这是 策略管理点 (PEP + PDP 合并)
public function enforce(string $action, string $resource, $user): string {
foreach ($this->policies as $policy) {
if ($policy['action'] !== $action) continue;
// 角色匹配
if ($policy['subject_role'] !== $user['role']) continue;
// 条件判断 (PIP)
if (isset($policy['condition'])) {
if ($policy['condition']['owner'] && $user['id'] !== $this->pip['resource_owner_id']) {
continue;
}
}
// 返回决策
return $policy['effect']; // 'allow' 或 'deny'
}
return 'deny'; // 默认拒绝
}
}
// 3. 使用示例
$pip = ['resource_owner_id' => 101];
$engine = new PolicyEngine($policyJson, $pip);
$user = ['role' => 'editor', 'id' => 100]; // 不是 owner
echo $engine->enforce('edit_document', 'doc_123', $user); // 输出 deny (因为不满足owner条件)
使用 责任链模式(Chain of Responsibility)
适用于多个策略需要依次判断(如:先判断IP白名单 -> 再判断用户角色 -> 再判断时间)。
<?php
// 抽象处理者
abstract class PolicyHandler {
protected ?PolicyHandler $next = null;
public function setNext(PolicyHandler $handler): PolicyHandler {
$this->next = $handler;
return $handler;
}
public function handle(array $request): ?bool {
$result = $this->process($request);
if ($result !== null) {
return $result; // 终止链
}
if ($this->next) {
return $this->next->handle($request);
}
return false; // 默认拒绝
}
abstract protected function process(array $request): ?bool;
}
// 具体策略节点
class IPCheckHandler extends PolicyHandler {
protected function process(array $request): ?bool {
$whitelist = ['192.168.1.1'];
if (in_array($request['ip'], $whitelist)) {
return null; // 继续下一个检查
}
return false; // IP不合法,直接拒绝
}
}
class RoleCheckHandler extends PolicyHandler {
protected function process(array $request): ?bool {
if ($request['role'] === 'admin') {
return true; // 管理员直接通过
}
return null; // 其他角色继续
}
}
// 构建责任链 (策略管理点)
$ipCheck = new IPCheckHandler();
$roleCheck = new RoleCheckHandler();
$ipCheck->setNext($roleCheck);
$result = $ipCheck->handle(['ip' => '192.168.1.2', 'role' => 'admin']);
// 结果:false (IP被拒绝)
生产环境建议
如果你的项目已经引入了 Symfony 或 Laravel 这类框架,可以利用现成的组件:
| 框架 | 对应组件 | 说明 |
|---|---|---|
| Laravel | Gate / Policy / Authorization |
内置授权策略,通过 AuthServiceProvider 注册策略类,使用 can() 或 authorize() 作为管理点。 |
| Symfony | Voter (投票器) |
实现 VoterInterface,通过 isGranted() 作为管理点,支持策略的多个属性组合判断。 |
| 通用PHP | PHP-CAS / OAuth2-PHP |
更偏向外部的 SSO 或 API 网关策略,策略点一般在中间件或网关中。 |
如何选择合适的策略管理点?
- 策略数量少且固定:使用策略模式(1个类对应1个策略)。
- 策略数量多、动态配置:使用JSON/DB配置 + 循环匹配(类似方式二)。
- 需要多级过滤:使用责任链模式。
- 使用现代框架:优先使用框架自带的Gate/Voter,因为它们与路由、中间件、依赖注入完美集成。
你需要根据具体的业务场景(如权限控制、价格计算规则、工作流审批规则)来决定采用哪种模式,如果方便,可以补充具体场景,我能给出更针对性的代码。