chore: 重写初始提交(清空历史,整理后全量提交)
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | YwxApp [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2026-2036 http://ywxapp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: ywxapp<admin@ywxapp.cn>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace addon\mqttbroker\command;
|
||||
|
||||
use think\console\Command;
|
||||
use think\console\Input;
|
||||
use think\console\Output;
|
||||
use think\console\input\Option;
|
||||
use addon\mqttbroker\service\Broker;
|
||||
|
||||
/**
|
||||
* 启动 MQTT Broker 常驻进程(兼容 MQTT 3.1.1 / 5.0,类 EMQX 轻量 broker)
|
||||
* php think mqttbroker:start
|
||||
* php think mqttbroker:start -p 1883
|
||||
*
|
||||
* 依赖:仅 Workerman\Worker(框架已自带,无需 composer require workerman/mqtt)。
|
||||
* 手动发布经 DB 出站队列内部路由,零外部依赖;仅"转发规则(桥接 EMQX)"
|
||||
* 需要 workerman/mqtt(composer require workerman/mqtt),未安装时自动跳过转发。
|
||||
*/
|
||||
class MqttBroker extends Command
|
||||
{
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
$this->setName('mqttbroker:start')
|
||||
->addOption('port', 'p', Option::VALUE_OPTIONAL, '监听端口', 1883)
|
||||
->addOption('host', 'H', Option::VALUE_OPTIONAL, '监听地址', '0.0.0.0')
|
||||
->setDescription('启动 MQTT Broker 服务 (MQTT 3.1.1 / 5.0)');
|
||||
}
|
||||
|
||||
|
||||
protected function execute(Input $input, Output $output)
|
||||
{
|
||||
$port = (int) $input->getOption('port');
|
||||
$host = $input->getOption('host');
|
||||
$output->writeln("启动 MQTT Broker on {$host}:{$port}(协议 MQTT 3.1.1 / 5.0)");
|
||||
$output->writeln("按 Ctrl+C 停止(Windows 下为单进程调试模式)");
|
||||
|
||||
(new Broker())->start($host, $port);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | YwxApp [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2026-2036 http://ywxapp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: ywxapp<admin@ywxapp.cn>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace addon\mqttbroker\command;
|
||||
|
||||
use think\console\Command;
|
||||
use think\console\Input;
|
||||
use think\console\Output;
|
||||
use think\facade\Db;
|
||||
use ywxapp\service\AddonService;
|
||||
use addon\mqttbroker\service\Auth;
|
||||
|
||||
/**
|
||||
* ACL 实网决策验证:用真实 DB 规则校验 Auth::checkAcl 的放行/拒绝逻辑。
|
||||
* php think mqttbroker:acltest
|
||||
* 验证项:deny 发布拒绝、默认放行、用户定向拒绝、超管绕过、$SYS 只读。
|
||||
* 不依赖运行中的 Broker,直接复用 Broker 实际调用的 Auth 逻辑。
|
||||
*/
|
||||
class TestAcl extends Command
|
||||
{
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
$this->setName('mqttbroker:acltest')
|
||||
->setDescription('验证 ACL 发布/订阅权限决策(含 deny 拒绝)');
|
||||
}
|
||||
|
||||
|
||||
protected function execute(Input $input, Output $output)
|
||||
{
|
||||
// 配置:开启 ACL,默认放行
|
||||
$saved = [];
|
||||
try { $saved = AddonService::config('mqttbroker') ?: []; } catch (\Throwable $e) {}
|
||||
$config = array_merge($saved, ['acl_enabled' => '1', 'acl_default' => 'allow']);
|
||||
|
||||
$auth = new Auth($config);
|
||||
$auth->ensureTables();
|
||||
|
||||
// 插入临时规则(测试后清理)
|
||||
$rows = [
|
||||
['target_type' => 'member', 'target' => 'alice', 'topic' => 'alice/secret', 'access' => 2, 'allow' => 0, 'sort' => 5, 'remark' => 'tmp'],
|
||||
['target_type' => 'all', 'target' => '', 'topic' => 'secret/#', 'access' => 2, 'allow' => 0, 'sort' => 10, 'remark' => 'tmp'],
|
||||
['target_type' => 'all', 'target' => '', 'topic' => 'public/#', 'access' => 3, 'allow' => 1, 'sort' => 20, 'remark' => 'tmp'],
|
||||
];
|
||||
$ids = [];
|
||||
foreach ($rows as $r) {
|
||||
$ids[] = Db::name('mqttbroker_acl')->insertGetId(array_merge($r, ['create_at' => time()]));
|
||||
}
|
||||
|
||||
$results = [];
|
||||
$chk = function (string $case, bool $got, bool $expect) use (&$results) {
|
||||
$results[$case] = ['got' => $got, 'expect' => $expect, 'ok' => $got === $expect];
|
||||
};
|
||||
|
||||
// 1) deny 发布 secret/# 被拒
|
||||
$chk('deny publish secret/#', $auth->checkAcl(null, 'c1', 'secret/data', Auth::ACT_PUB), false);
|
||||
// 2) 同一主题仅 deny 发布,订阅走默认放行
|
||||
$chk('subscribe secret/# default-allow', $auth->checkAcl(null, 'c1', 'secret/data', Auth::ACT_SUB), true);
|
||||
// 3) allow 规则 public/# 发布放行
|
||||
$chk('allow publish public/info', $auth->checkAcl(null, 'c1', 'public/info', Auth::ACT_PUB), true);
|
||||
// 4) 未命中规则走默认放行
|
||||
$chk('default allow other/topic', $auth->checkAcl(null, 'c1', 'other/topic', Auth::ACT_PUB), true);
|
||||
// 5) 用户定向 deny:alice 发布 alice/secret 被拒
|
||||
$chk('user alice deny publish', $auth->checkAcl('alice', 'cA', 'alice/secret', Auth::ACT_PUB), false);
|
||||
// 6) alice 订阅 alice/secret(user 规则仅限发布)走默认放行
|
||||
$chk('user alice subscribe (rule is pub-only)', $auth->checkAcl('alice', 'cA', 'alice/secret', Auth::ACT_SUB), true);
|
||||
// 7) 超管绕过 deny
|
||||
$chk('superuser bypass deny', $auth->checkAcl('root', 'cR', 'secret/data', Auth::ACT_PUB, true), true);
|
||||
// 8) $SYS 只读:订阅放行、发布拒绝
|
||||
$chk('$SYS subscribe allowed', $auth->checkAcl(null, 'c2', '$SYS/broker/uptime', Auth::ACT_SUB), true);
|
||||
$chk('$SYS publish denied', $auth->checkAcl(null, 'c2', '$SYS/broker/uptime', Auth::ACT_PUB), false);
|
||||
|
||||
// 清理临时规则
|
||||
if ($ids) {
|
||||
Db::name('mqttbroker_acl')->whereIn('id', $ids)->delete();
|
||||
}
|
||||
|
||||
$pass = 0;
|
||||
$fail = 0;
|
||||
foreach ($results as $case => $r) {
|
||||
$flag = $r['ok'] ? 'PASS' : 'FAIL';
|
||||
if ($r['ok']) { $pass++; } else { $fail++; }
|
||||
$output->writeln("[{$flag}] {$case} (got=" . var_export($r['got'], true) . " expect=" . var_export($r['expect'], true) . ")");
|
||||
}
|
||||
$output->writeln("");
|
||||
$output->writeln("ACL 验证结果:PASS={$pass} FAIL={$fail}");
|
||||
return $fail === 0 ? 0 : 1;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user