分布式服务,是将多个具有不同或相同功能的服务分散在不同的服务器上,对外提供服务。
那么在分布式服务中,使用 PHP-Casbin 作为权限控制时,不同服务器上的服务的策略要保证是同步的。这里我们主要探讨常驻内存的 PHP 服务,在常驻内存的服务中,PHP-Casbin 一般是单例模式,所有的策略都会加载到内存,性能出色。
PHP-FPM 下每次都重新初始化 Enforcer
并重新加载策略,不需要做额外的策略同步。
在 Casbin
中提供了 Watcher
,用于多实例间的消息策略同步。
原理
当某个实例的Enforcer
中的策略发生变化时,调用 Watcher
,向消息队列(MQ)中推送消息,监听到该消息队列的Enforcer
收到消息后,自动刷新
当前实例中的策略。
主要是在常驻进程的框架中使用 Casbin ,例如:Swoole、WorkerMan、ReactPHP 等。
第一种是单实例、多进程,进程中的数据相互隔离的;第二种则是多实例的场景。
环境
这里采用 PHP 8.4
、Swoole
作为演示环境,并且借助 Redis watcher for PHP-Casbin in Swoole 作为 Watcher
。
使用composer
安装一下依赖:
composer require casbin/casbin
composer require casbin/dbal-adapter
composer require casbin/swoole-redis-watcher
编码
初始化 Swoole
的 Server
,使用 swoole 启动一个HTTP服务常驻内存。
use Casbin\Enforcer;
use CasbinAdapter\DBAL\Adapter;
use CasbinWatcher\SwooleRedis\Watcher;
use Swoole\Http\Server;
Co::set(['hook_flags' => SWOOLE_HOOK_ALL]);
$serv = new Server('127.0.0.1', 9501);
$serv->set(['worker_num' => 4]);
在服务启动后,注入回调函数,初始化Casbin
的决策器。
$serv->on('WorkerStart', function($server, $worker_id) {
global $enforcer;
$adapter = Adapter::newAdapter([
'driver' => 'pdo_mysql',
'host' => '127.0.0.1',
'dbname' => 'test',
'user' => 'root',
'password' => '',
'port' => '3306',
]);
$enforcer = new Enforcer('./path/to/model.conf', $adapter);
// 设置 Watcher
$watcher = new Watcher([
'host' => '127.0.0.1',
'password' => '',
'port' => 6379,
'database' => 0,
]);
$enforcer->setWatcher($watcher);
});
$serv->start();
可以看到,在初始化决策器后,又初始化了Watcher
,并调用决策器(Enforcer
)设置Watcher
。
Swoole Watcher 是一个通过 redis
的发布
和订阅
功能实现的消息生产和消费的。在 swoole 中使用协程异步非阻塞订阅 redis
的消息,收到消息后触发回调,随后调用决策器的loadPolicy()
,重新加载策略从而实现不同实例的策略更新。
最后
本文介绍了如何在分布式多实例的架构下实现 Casbin
的策略同步,随着新技术的不断涌现,如今的 PHP
已经不再是完全依赖 PHP-FPM
来运行,不只是 Swoole
,还有 FrankenPHP
RoadRunner
ReactPHP
WorkerMan
等框架为 PHP
提供了运行环境来为 PHP 加速。
PHP-Casbin
还有非常多的扩展,为各种各样的框架集成提供了便利,可以查看 GitHub 仓库:https://github.com/php-casbin 。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。