# 边缘设备自动接入实施方案 > 状态:设计待实施 > > 适用对象:车牌识别相机、道闸控制器、边缘网关等支持局域网配置的设备 > > 关联文档:doc/设备端对接文档.md、doc/设备接入层设计.md --- ## 1. 目标与边界 当前 MQTT 接入方式要求边缘设备预先知道管理系统的 Broker 地址,再由设备主动建立 MQTT 连接。该前置配置对现场部署不友好,尤其是在管理系统 IP 变化、设备批量安装或设备恢复出厂设置时。 本方案增加一条只用于首次接入和重新配置的局域网通道,使管理系统可以发现待接入设备,并向设备下发 MQTT 连接参数。设备完成配置后,仍按既有 MQTT 协议工作;车辆识别、开关闸、状态上报和支付等正常业务流程不使用发现通道。 本期范围: - 管理系统发现局域网内未配置或待重新配置的边缘设备。 - 当 UDP 自动发现不可用时,管理员可以通过设备 IP 和 HTTPS 端口走正式的手工接入路径;该路径属于生产接入能力,不是临时排障开关。 - 管理系统向经管理员确认的设备下发 Broker 地址、设备编码、通道坐标和认证信息。 - 设备保存配置,主动连接 MQTT Broker,并通过 gate.state.v1 上报在线状态。 - 管理系统根据 MQTT 状态完成接入确认。 不在本期范围: - 跨网段、互联网或 NAT 环境下的 UDP 自动发现。该场景可以使用本方案的手工 IP 接入,也可以使用边缘网关、VPN 或云端设备管理平台。 - 对不支持 UDP 发现或不提供配置接口的既有设备进行强制接入。管理系统不能控制完全未知的设备。 - 用 UDP 传输车牌、图片、道闸控制等业务消息。UDP 只承担发现与引导配置。 ## 2. 核心结论 设备在不知道 Broker 地址时尚未连接 MQTT。此时管理系统无法通过 MQTT 获得设备 IP,也无法通过 MQTT 下发 Broker 配置。因此,系统主动获取 IP 并下发连接参数,必须建立在边缘端预置接入代理的前提上。 完整过程如下: 1. 边缘设备监听固定的局域网发现端口。 2. 管理系统通过 UDP 定向广播发送发现请求。 3. 设备以 UDP 单播回复设备身份、源 IP、配置端口和证书指纹。 4. 管理系统要求管理员完成设备身份确认并选择业务通道。 5. 管理系统通过设备的 HTTPS 配置接口下发 MQTT 参数。 6. 设备原子保存配置,主动连入 MQTT Broker。 7. 设备清除旧离线遗嘱,发布 retained 的 gate.state.v1。 8. 管理系统收到状态消息后将设备标记为已接入并在线。 UDP 广播优于扫描整个 IP 网段:不需要假设网段范围,不会主动连接无关设备,响应速度快,也便于交换机和防火墙按固定端口放行。 UDP 发现失败时,系统不能把“没有发现设备”解释为“设备不存在”。管理员应切换到手工 IP 接入,通过 HTTPS 直接读取设备身份并完成同一套核验、绑定、配置和 MQTT 上线确认。 ## 3. 总体架构 ~~~text 管理系统 边缘设备 | | | UDP 广播 discovery.request.v1 | |--------------------------------------------->| | | | UDP 单播 discovery.response.v1 | |<---------------------------------------------| | | | 管理员确认设备、停车场、岗亭和通道 | | | | HTTPS POST /api/v1/provision | |--------------------------------------------->| | | 保存配置、重启 MQTT 客户端 | | | MQTT CONNECT | |<---------------------------------------------| | | | MQTT retained gate.state.v1 | |<---------------------------------------------| | | | 接入状态更新为 已接入/在线 | ~~~ | 通道 | 用途 | 生命周期 | 可靠性要求 | | --- | --- | --- | --- | | UDP 31001 | 发现待接入设备 | 仅配置前或人工重新配置 | 可重试,不承载敏感配置 | | HTTPS 8443 | 下发、查询和撤销设备配置 | 配置阶段 | 必须鉴权、签名、幂等 | | MQTT 1883 或 TLS 8883 | 状态、识别事件、指令和回执 | 正常运营阶段 | QoS 1、LWT、retained state | 端口是建议默认值,最终允许设备固件和系统配置覆盖。管理系统侧端口必须在 Windows 防火墙和现场网络策略中放通。 ## 4. 状态模型 设备接入状态与设备在线状态是两个不同维度,不能继续只使用现有设备表中的 online 或 offline。 | 接入状态 provision_status | 含义 | 允许操作 | | --- | --- | --- | | unprovisioned | 已发现但未绑定业务通道 | 查看详情、发起配置 | | provisioning | 管理系统正在下发配置 | 查询进度、取消或重试 | | provisioned | 设备已确认保存配置,尚未收到 MQTT 在线状态 | 修改配置、等待上线 | | online | MQTT gate.state.v1 已确认 | 正常通行、重新配置 | | offline | 已接入设备当前无 MQTT 状态 | 查看原因、重新配置 | | failed | 最近一次配置失败 | 查看错误、修正后重试 | 在线状态仍由 MQTT 维护。管理系统启动时会将启用 MQTT 设备暂置为 offline,收到 retained 的 gate.state.v1 后恢复 online。配置接口返回成功不等于设备已在线,必须收到 MQTT 状态消息才能认为接入完成。 ## 5. 数据设计 建议在现有 uhf_reader 中补充以下字段,避免新建一张与设备主数据重复的表。 | 字段 | 类型 | 说明 | | --- | --- | --- | | provision_status | varchar(20) | 接入状态,默认 unprovisioned | | provision_method | varchar(20) | 接入方式,取 auto_udp 或 manual_ip | | provision_error | varchar(500) | 最近一次失败原因 | | provisioned_at | datetime | 设备确认保存配置的时间 | | last_discovered_at | datetime | 最近一次发现响应时间 | | discovered_ip | varchar(50) | 最近一次发现到的 IP,仅作辅助信息 | | config_port | int | 设备 HTTPS 配置端口 | | device_model | varchar(100) | 设备型号 | | firmware_version | varchar(100) | 固件版本 | | device_public_key | text | 设备身份公钥或证书指纹 | 现有 ip_address 保留为管理员确认后的设备管理地址。discovered_ip 是一次发现结果,未经管理员确认时不能覆盖已生效的管理地址。 建议增加 device_discovery 临时表保存发现结果,字段至少包括 request_id、device_id、source_ip、payload、verified、expired_at 和 created_at。发现记录默认 10 分钟过期,管理员确认绑定后再创建或更新 uhf_reader。 ## 6. 发现协议 ### 6.1 UDP 约束 - 传输:IPv4 UDP。 - 默认端口:31001。 - 广播地址:优先使用本机网卡的定向广播地址,例如 192.168.10.255;允许管理员选择目标网卡或指定广播网段。 - 请求重试:连续发送 3 次,间隔 500ms;收集响应窗口为 3 秒。 - 单包上限:4KB;超出限制或 JSON 非法时直接丢弃。 - 响应仅用于展示和建立 HTTPS 配置连接,不能据此直接开闸或修改业务数据。 ### 6.2 广播请求 discovery.request.v1 ~~~json { "schema": "discovery.request.v1", "request_id": "7ba3a5ea-3ca4-45fe-b59d-1dc47b6abda5", "issued_at": 1760000000, "expires_at": 1760000030, "system_id": "parking-system-001", "nonce": "base64-random-32-bytes" } ~~~ | 字段 | 必填 | 说明 | | --- | --- | --- | | schema | 是 | 固定 discovery.request.v1 | | request_id | 是 | UUID,用于关联响应 | | issued_at / expires_at | 是 | Unix 秒,最长有效期 30 秒 | | system_id | 是 | 管理系统安装实例标识 | | nonce | 是 | 32 字节随机值,防止响应重放 | ### 6.3 单播响应 discovery.response.v1 ~~~json { "schema": "discovery.response.v1", "request_id": "7ba3a5ea-3ca4-45fe-b59d-1dc47b6abda5", "device_id": "SN-20260819-0001", "device_code": "EDGE-A01", "device_type": "lpr-gate", "device_model": "LPR-GW-200", "firmware_version": "2.1.0", "ip": "192.168.10.26", "config_url": "https://192.168.10.26:8443/api/v1/provision", "public_key_fingerprint": "SHA256:...", "signing_public_key": "base64-ed25519-public-key", "nonce": "base64-random-32-bytes", "signature": "base64-signature" } ~~~ 管理系统校验规则: 1. request_id 和 nonce 必须与当前未过期发现任务一致。 2. 响应中的 ip 必须等于 UDP 报文源 IP,防止响应将系统引导到第三方地址。 3. config_url 的主机必须等于 UDP 源 IP,且只允许 HTTPS。 4. device_id 是永久硬件身份;device_code 是业务编码,管理员确认后可覆盖。 5. 系统必须校验 signature。`signing_public_key` 必须是 Base64 编码的 Ed25519 公钥,其 SHA256 必须与 `public_key_fingerprint` 一致;签名载荷以换行符连接 `schema`、`request_id`、`device_id`、`ip`、`config_url`、`nonce`,顺序固定。首次信任仍须通过扫描设备标签二维码或输入一次性配对码完成。 ## 7. 配置下发协议 ### 7.1 传输方式 管理系统使用 HTTPS 调用设备的 POST /api/v1/provision。不能使用裸 TCP 或 UDP 承载配置命令,因为 Broker 地址、设备凭据和通道坐标均属于敏感配置。 首次部署可采用设备出厂自签名证书,但管理系统必须将响应中的公钥指纹与设备标签或二维码中的指纹比对。生产环境推荐每台设备预置证书并使用双向 TLS。 ### 7.2 配置请求 provision.request.v1 ~~~json { "schema": "provision.request.v1", "request_id": "f0f2f011-cc14-4965-8a61-9a65b3ec2f0b", "issued_at": 1760000000, "expires_at": 1760000060, "device_id": "SN-20260819-0001", "device_code": "CAM-A01", "mqtt": { "host": "192.168.10.10", "port": 8883, "tls": true, "client_id": "CAM-A01", "username": "device/CAM-A01", "password": "one-time-bootstrap-token", "keep_alive_seconds": 30 }, "route": { "parking_lot_id": 2, "booth_id": 2, "channel_id": 2, "direction": "in" }, "topic_prefix": "parking", "config_version": 1, "nonce": "base64-random-32-bytes", "signature": "base64-signature" } ~~~ 字段及处理要求: - mqtt.host 必须是设备可访问的局域网 IP 或 DNS 名称。系统必须拒绝下发 127.0.0.1、localhost 和 0.0.0.0。 - 管理系统新增 mqtt.advertised-host、mqtt.advertised-port 和 mqtt.tls-enabled 配置,用于下发给设备;不能从 mqtt.broker 自动推导,因为后者可能包含系统本机地址。 - mqtt.client_id、device_code 和 MQTT 用户名一一对应。 - password 为一次性引导令牌;设备首次成功连接后应换取长期设备凭据,不能复用管理账户、数据库密码或公共密码。 - route 仅能由管理员在页面上确认的停车场、岗亭和通道生成。设备不得自行声明业务坐标。 - 相同 request_id 重复提交时,设备必须返回第一次处理结果,保证幂等。 - 设备必须原子写入配置:写入失败时保留旧配置,不能只更新 Broker 地址而遗漏通道坐标。 ### 7.3 配置响应 provision.response.v1 ~~~json { "schema": "provision.response.v1", "request_id": "f0f2f011-cc14-4965-8a61-9a65b3ec2f0b", "result": "accepted", "message": "configuration saved; mqtt reconnecting", "config_version": 1, "applied_at": 1760000002, "signature": "base64-signature" } ~~~ accepted 只表示设备已保存并准备重连,不代表 MQTT 已在线。管理系统在 30 秒内等待目标设备的 retained gate.state.v1;收到后标记 online,超时则标记 failed 并记录诊断原因。 ## 8. 配置完成后的 MQTT 行为 设备保存配置并连接 Broker 后,必须按现有设备端对接文档执行以下动作: 1. 使用 device_code 作为 MQTT ClientID。 2. 配置 QoS 1、Keep Alive 30 秒和 retained LWT。 3. 订阅自身通道的 gate/cmd Topic。 4. 向 gate/lwt 发布 retained 空载荷,清除上一次异常断开遗留的离线遗嘱。 5. 立即发布 retained 的 gate.state.v1。 6. 相机使用 camera.event.v1 上报识别事件;道闸使用 gate.cmd.v1 和 gate.ack.v1 收发命令和回执。 第 4 步不可省略。设备发生过异常断线时,旧的 retained LWT 可能在管理系统重启订阅后覆盖新的在线状态。 ## 9. 管理系统改造设计 ### 9.1 后端模块边界 新功能按领域放入 internal/modules/device-provisioning,不直接塞入旧 internal/service/uhf。 ~~~text internal/modules/device-provisioning/ ├── api.go ├── service/ │ ├── discovery.go │ ├── provisioning.go │ ├── signature.go │ └── service.go ├── repository/ │ └── repo.go └── model/ ├── request/ └── response/ ~~~ | 组件 | 职责 | | --- | --- | | discovery.go | 枚举本机 IPv4 网卡,发送定向广播,校验响应,缓存发现结果 | | provisioning.go | 校验管理员授权和业务绑定,调用设备 HTTPS 接口,等待 MQTT 确认 | | signature.go | HMAC 或 Ed25519 签名、Nonce、过期时间和证书指纹验证 | | repository | 保存临时发现记录、接入状态及审计信息 | | 既有 MQTT 模块 | 继续处理正常业务消息与在线状态,不处理 UDP 和 HTTPS 配置细节 | ### 9.2 管理 API 以下 API 必须只授予管理员角色: | 方法 | 路径 | 用途 | | --- | --- | --- | | POST | /device-provisioning/discover | 开始一次 3 秒局域网发现 | | GET | /device-provisioning/discoveries | 查询未过期发现结果 | | POST | /device-provisioning/:device_id/verify | 校验二维码、配对码或证书指纹 | | POST | /device-provisioning/:device_id/provision | 绑定停车场、岗亭、通道并下发 MQTT 配置 | | GET | /device-provisioning/:device_id/status | 查询配置、MQTT 确认和错误详情 | | POST | /device-provisioning/:device_id/revoke | 让设备删除 MQTT 凭据并回到待配置状态 | 所有接口记录操作日志,至少包含操作人、目标硬件 ID、发现源 IP、配置前后路由、执行结果和失败原因。 ### 9.3 前端页面流程 设备管理页面增加自动发现设备入口,但不替换既有 TCP 或串口手工新增方式。 1. 管理员选择停车场后点击发现设备。 2. 页面展示设备型号、序列号、IP、固件版本、信任状态和上次发现时间。 3. 管理员核对设备物理标签或扫描二维码,完成首次信任。 4. 管理员填写或确认设备名称、设备编码、设备类型、岗亭和通道。 5. 页面展示将下发的 Broker 地址、端口、TLS 状态和 Topic,不显示密码明文。 6. 管理员确认后开始配置,页面显示配置中。 7. 收到 MQTT 状态后显示在线;超时显示配置已保存但未上线,并提供诊断和重试。 设备编码冲突、通道已经绑定独占设备、设备型号不支持所选功能时,必须在配置下发前阻断。 ### 9.4 手工输入设备 IP 的正式备用接入 手工 IP 接入与 UDP 自动发现是两条并列的生产接入路径。它不绕过身份核验、管理员授权、业务绑定或 MQTT 上线确认;唯一差别是设备地址由管理员输入,系统不依赖 UDP 广播获得地址。 #### 适用场景 以下任一情况成立时,管理员可以选择“手工输入 IP”入口: - 管理系统与设备跨 VLAN,路由器不转发 UDP 广播; - 交换机或防火墙禁止 UDP 广播; - 无线网络启用了客户端隔离,设备不能接收管理系统的广播; - 管理员通过 VPN 访问现场网络,广播域无法穿透 VPN; - 设备固件不支持本方案的 UDP 发现协议,但提供 HTTPS 配置接口。 手工 IP 接入应在发现任务无结果、发现明确失败或管理员确认网络不支持广播时使用。系统应在接入记录中保存 `provision_method=manual_ip`,便于审计和后续运维统计。 #### 页面流程 1. 管理员在设备管理页面选择“手工输入 IP”,填写设备 IPv4 地址和 HTTPS 端口(默认 8443);端口必须是设备实际配置接口端口,不能把 MQTT 端口当作配置端口。 2. 页面先在客户端和服务端校验 IP、端口及当前管理员权限,通过校验后才允许发起连接。页面明确提示这是正式接入流程,不能用于跳过设备身份确认。 3. 系统使用 HTTPS `GET /api/v1/identity`(或设备端对接文档约定的身份查询接口)读取设备永久 ID、型号、固件版本、当前设备编码、证书公钥指纹和配对状态;读取失败不得创建或覆盖设备主数据。 4. 管理员核对设备机身标签或二维码,确认 HTTPS 证书指纹,并输入一次性配对码(设备没有配对码时必须由受控的标签或初始化凭据替代)。证书指纹或配对码不匹配时停止流程,不能仅凭 IP 继续。 5. 身份确认成功后,管理员选择并确认停车场、岗亭、通道、方向和设备业务编码。系统检查设备编码冲突、通道独占约束和设备能力,不满足时在下发前阻断。 6. 页面展示待下发的 Broker 地址、端口、TLS、ClientID、Topic 和业务坐标,密码或一次性引导令牌只显示掩码。管理员二次确认后,系统通过同一 HTTPS 配置接口下发 MQTT 配置并记录请求 ID。 7. 页面进入“配置中/等待 MQTT 上线”,在 30 秒内等待目标设备发布 retained `gate.state.v1`。收到且设备永久 ID、业务坐标和配置版本一致后标记“已接入/在线”;超时显示“配置已保存但未上线”,保留诊断和重试入口。 #### IP 与 HTTPS 端口校验 校验必须在前端和后端各执行一次,后端校验结果为准。输入框只接受字面 IP,不解析主机名或通过 DNS 重定向到其他地址。 | 输入 | 处理 | | --- | --- | | `127.0.0.1`、任意 IPv4 `127.0.0.0/8` | 拒绝,禁止连接管理系统本机回环地址 | | `localhost`(不区分大小写)及其他主机名 | 拒绝,手工入口只接受 IP | | `0.0.0.0`、IPv4 未指定地址 `0.0.0.0/32` | 拒绝,不允许把监听地址当作设备地址 | | IPv4 定向广播地址(按管理系统网卡子网计算的主机位全 1)和 `255.255.255.255` | 拒绝,禁止把广播地址当作单台设备 | | IPv4 组播 `224.0.0.0/4`、IPv6 组播 `ff00::/8` | 拒绝,禁止通过组播地址连接配置接口 | | IPv6 回环 `::1`、未指定地址 `::` | 拒绝;若设备支持 IPv6,必须使用字面地址并按 HTTPS URL 规则加方括号 | | 其他合法单播 IP | 允许进入 HTTPS 身份读取阶段,但仍须通过证书指纹、永久 ID 和配对码确认 | | HTTPS 端口 | 仅允许 1-65535 的整数;连接必须使用 HTTPS,端口不可为空、不可为负数或超范围 | 检测定向广播地址时使用管理系统当前网卡和路由表计算,不把任意普通主机地址误判为广播。连接期间禁止跟随 HTTP 重定向到不同主机;最终连接地址必须仍是管理员输入的 IP。 #### 手工接入状态和异常处理 手工流程沿用 `provision_status`,并增加 `provision_method` 和阶段错误码,避免把“身份未确认”和“MQTT 未上线”混为同一种失败: | 状态/阶段 | 含义与处理 | | --- | --- | | manual_input | 已提交 IP 和端口,正在做本地及服务端格式校验 | | manual_connecting | 正在建立 HTTPS 连接和读取设备身份;超时可重试,不改变既有设备配置 | | identity_unverified | 已读取身份,等待证书指纹和配对码确认;此状态禁止下发配置 | | manual_verified | 身份已确认,等待管理员完成停车场/岗亭/通道绑定和二次确认 | | provisioning | 已通过 HTTPS 下发 MQTT 配置,等待设备回执 | | provisioned | 设备已确认保存配置,尚未收到 `gate.state.v1` | | online | 收到并校验目标设备的 `gate.state.v1` | | failed | 任一阶段失败;保存阶段、错误码、原始 IP、端口和 request_id,修正后可重试 | IP 不合法、端口不可用、HTTPS 证书不匹配、设备永久 ID 与既有记录不一致、配对码错误、设备拒绝配置、Broker 不可达或 30 秒未上线,都必须显示可操作的原因。重试只能从失败阶段重新开始;身份未确认或身份冲突时,必须重新执行身份确认,不能复用旧的信任结果。 ## 10. 安全要求 自动发现降低部署成本,也扩大局域网攻击面。以下是上线前最低要求: 1. 发现请求不得携带 Broker 密码、设备密钥和停车场业务数据。 2. 发现响应与配置请求必须带 request_id、nonce、签发时间和过期时间。 3. 设备使用预置私钥对响应和配置结果签名;管理系统使用设备公钥或证书指纹验证。 4. 管理系统配置请求同样必须由安装密钥签名;设备拒绝未签名、过期或重放请求。 5. 配置接口必须使用 HTTPS;生产环境使用双向 TLS。 6. MQTT 应从当前匿名接入升级为设备级账号或证书,并按 device_code 限制 Topic ACL。 7. 配置失败、设备身份不一致、证书变化和重复配对都记录异常或审计日志。 8. 发现接口不能覆盖已在线设备的配置;重新配置必须由管理员显式发起。 9. 不得将 MQTT 管理账户、数据库密码和长期系统 JWT 下发给边缘端。 10. 手工 IP 接入必须使用 HTTPS;系统固定校验证书公钥指纹,并禁止跟随到其他主机的重定向。 11. 每次手工接入都必须核对设备永久 ID 与证书/配对码,永久 ID 不得由管理员输入,也不能只以 IP 作为设备身份。 12. 手工接入入口和重新配置入口只授予管理员;操作审计至少记录操作人、输入 IP、HTTPS 端口、证书指纹、永久 ID、配对结果、绑定前后路由、request_id、结果和失败原因,敏感令牌不得写入日志。 ## 11. 异常与恢复策略 | 场景 | 系统处理 | | --- | --- | | 未发现设备 | 显示未发现,提示检查供电、同网段、防火墙和 UDP 端口 | | 响应 IP 与 UDP 源 IP 不一致 | 丢弃响应并记录安全日志 | | 设备证书指纹不匹配 | 禁止配置,要求管理员重新确认物理身份 | | HTTPS 配置超时 | 标记 failed,不修改既有已生效设备路由 | | 设备返回已保存但 30 秒未 MQTT 上线 | 标记 provisioned 或 failed,提示检查 Broker IP、防火墙和凭据 | | MQTT 连上后再次离线 | 复用既有 LWT、重连和状态恢复机制,更新 offline | | 管理系统重启 | MQTT 设备先保守 offline,收到 retained gate.state.v1 后恢复 online;发现任务不恢复 | | 网络 IP 变化 | 重新发现后展示新的 discovered_ip,管理员确认后可以重新下发配置 | | UDP 自动发现不可用 | 转入手工 IP 入口;不降低 HTTPS、证书指纹、永久 ID、配对码和管理员授权要求 | | 手工输入 IP 不合法或为回环/广播/组播地址 | 本地和服务端均拒绝,不能发起网络连接,并提示修正地址 | | 手工 IP 的 HTTPS 端口拒绝连接或超时 | 保持既有配置和绑定不变,状态为 failed,记录端口、错误码并提供重试 | | 手工 IP 身份接口返回的永久 ID 已绑定其他设备 | 阻断流程并记录安全审计,不得覆盖原设备或按新设备创建 | | 手工 IP 证书指纹或配对码不匹配 | 状态为 identity_unverified/failed,禁止下发 MQTT 配置,要求重新核对现场标签 | ## 12. 分阶段实施计划 ### 阶段 1:协议与基础数据 - 确认边缘端固件能提供 UDP 发现监听和 HTTPS 配置 API。 - 确认永久设备 ID、设备证书或密钥的出厂写入方式。 - 为 uhf_reader 和临时发现记录增加接入状态字段。 - 新增 mqtt.advertised-host、mqtt.advertised-port、mqtt.tls-enabled 配置。 - 冻结 discovery.*.v1 与 provision.*.v1 的 JSON Schema。 验收:模拟边缘端能响应发现请求,管理系统能校验并保存发现记录。 ### 阶段 2:管理系统发现与页面 - 实现 device-provisioning 后端模块、管理 API 与权限。 - 实现多网卡定向广播,不使用全网段端口扫描。 - 在设备管理页面增加待接入设备列表、手工 IP 接入、身份核验和通道绑定流程。 - 增加操作日志与异常记录。 验收:管理员可发现多个模拟设备;在跨 VLAN 或 UDP 被禁时,可通过手工 IP 完成身份核验和通道绑定;未核验设备不能下发配置。 ### 阶段 3:安全配置下发 - 实现 HTTPS 配置请求、证书指纹校验、签名、Nonce 与幂等处理。 - 实现一次性 MQTT 引导令牌和设备级 MQTT 账号或 ACL。 - 实现配置回执、30 秒 MQTT 确认等待和失败诊断。 验收:未配置设备可绑定到指定通道并上线;错误 Broker 地址能诊断为配置已保存但未上线。 ### 阶段 4:现场联调与恢复演练 - 覆盖管理系统重启、Broker 重启、设备断电、设备换 IP、重复配置与恶意响应。 - 确认边缘端清除旧 retained LWT 后再发布 retained state。 - 完成防火墙、交换机 VLAN、TLS 证书和备份恢复检查。 验收:发现、身份确认、配置、MQTT 在线、车牌入场、开闸回执、设备离线和重连恢复全流程可重复通过。 ## 13. 测试清单 | 分类 | 用例 | 预期结果 | | --- | --- | --- | | 发现 | 同一网段 1 台设备 | 3 秒内出现 1 条待接入记录 | | 发现 | 同一网段 20 台设备同时响应 | 按 device_id 去重展示,无阻塞 | | 发现 | 伪造 request_id 或过期响应 | 被丢弃并记录安全日志 | | 发现 | 响应载荷大于 4KB | 被丢弃,不影响服务 | | 配置 | 正确签名和证书 | 设备保存配置并 MQTT 上线 | | 配置 | 错误签名、过期时间或硬件 ID | 设备拒绝,系统显示失败原因 | | 配置 | 相同 request_id 重试 | 设备幂等返回,不重复重启或创建凭据 | | MQTT | Broker 地址为 127.0.0.1 | 下发前拒绝 | | MQTT | Broker 防火墙未放行 | 配置保存后 30 秒未上线,给出诊断 | | 恢复 | 管理系统重启 | retained state 使设备恢复在线 | | 恢复 | 设备断电再上线 | LWT 离线,清除旧 LWT 并发布 state 后恢复在线 | | 权限 | 操作员调用配置 API | 无权限,不能下发配置 | | 手工接入 | 输入 `127.0.0.1`、`localhost`、`0.0.0.0` | 前后端均拒绝,不发起 HTTPS 连接 | | 手工接入 | 输入 IPv4 定向广播、`255.255.255.255` 或 IPv4/IPv6 组播地址 | 拒绝并提示地址不能指向广播或组播 | | 手工接入 | 输入合法单播 IP 和有效 HTTPS 端口 | 成功读取身份,进入证书/配对码确认,不自动下发配置 | | 手工接入 | 端口为空、非整数、0、负数或大于 65535 | 拒绝提交,不能建立连接 | | 手工接入 | HTTPS 证书指纹与标签不一致 | 阻断配置并写入安全审计,设备保持原配置 | | 手工接入 | 永久 ID 与已有设备记录不一致或已被绑定 | 阻断配置,不创建重复设备,不覆盖原绑定 | | 手工接入 | 配对码错误、过期或重复使用 | 身份保持未确认,限制重试并记录审计 | | 手工接入 | 正确身份确认后绑定停车场/岗亭/通道并下发 | 设备返回 accepted,等待 `gate.state.v1` 后才标记 online | | 手工接入 | HTTPS 配置成功但 30 秒未收到 `gate.state.v1` | 标记 provisioned 或 failed,展示 Broker、防火墙和凭据诊断,可重试 | | 手工接入 | 非管理员访问手工接入、身份确认或配置 API | 返回无权限,不读取身份、不下发配置,并记录审计 | | 手工接入 | 管理员完成一次成功接入 | 审计包含操作人、IP、端口、证书指纹、永久 ID、绑定和结果,不记录令牌明文 | ## 14. 上线前决策 实施前必须确认以下事项: 1. 边缘端是否由本项目团队控制固件,能否实现 UDP 与 HTTPS 接入代理。 2. 现场网络是否允许 UDP 广播;若不允许,单台或少量设备使用本方案手工 IP 接入,批量设备再评估边缘网关、VPN 或 mDNS 方案。 3. 管理系统是否有稳定的局域网 IP 或 DNS 名称。这是 mqtt.advertised-host 的前提。 4. MQTT 是否在本期升级到 TLS 和设备级账号。生产环境不建议延续匿名 Broker。 5. 设备与通道是否一对一。若一台网关代理多台相机或道闸,永久设备 ID 与业务设备编码必须分开建模。 在上述前提未确认前,不应将主动获取 IP、下发 Broker 地址的逻辑直接写入既有 MQTT 开关闸代码。该能力属于设备首次接入和配置管理,不属于正常通行控制。