# 访客无鉴权策略验证-操作手册(发布版) ## 1. 适用范围 - 目标:验证无鉴权模式下访客接口是否可调用,以及“黄平访问蒙海文”是否触发策略。 - 环境:生产环境(建议低峰时段执行)。 - 对应版本:`cw-elevator-application-2.0.9` - 建议先读:`执行流程设计-简化版.md`(先定流程,再执行) ## 2. 前置条件 1. Python 3.8+ 2. **推荐(与 §4.0 一致)**:`python3 -m pip install -r python/requirements-min.txt`(安装 `requests`)。若仅单笔安装亦可:`python3 -m pip install requests`。 3. 关键参数确认: - `businessId=2524639890ba4f2cba9ba1a4eeaa4015` - `蒙海文personId=964454497399468032` - `黄平personId=1102270499947507712` - `黄平姓名=黄平`、`手机号=13926442944`(仅用于人工核对) 说明: - 被访者ID参数为 `--meng-person-id`,默认即 `964454497399468032`,可按现场覆盖。 ## 3. 手工 SQL(访客 ID 复核) 见:`sql/黄平访客ID手工查询.sql` ## 3.1 策略基线核查 SQL(必须先执行) 见:`sql/租户访客策略基线核查.sql` 重点核验: - `business_id='2524639890ba4f2cba9ba1a4eeaa4015'` - `policy_type='INTERSECT_ALLOWLIST'` - `enabled=1` - `allow_zone_ids` 包含 `605560545117995008`(28F) - 同租户 `building_id` 为空的默认策略仅 1 条 - 策略语义(**规范**):启用策略时 **`allow_zone_ids` 在组织 `detail` 以「替代」写入 `floorList`**;电梯 **`addVisitor`** 仅透传 **`detail.floorList`**(UC-01)或请求 **`floorIds`**(UC-02),**不与 allow 求交**。失效场景以 **`76260531`** 等为准(历史 **`76260532`** 交集失败路径已废止)。详见 [`visitor-registration-business-flow.md`](../visitor-registration-business-flow.md)、[`租户组织人员访客-数据模型与用例.md`](../../architecture/租户组织人员访客-数据模型与用例.md)。 ## 3.2 多公司多部门样本筛选 SQL(第二步) 见:`sql/批量样本筛选-多公司多部门.sql` 筛选结果请保存为 `sql/batch_cases.csv`,列头要求: `business_id,meng_person_id,company,department` ## 4. 执行步骤 ### 4.0 标准预置 25 人批量(推荐,单行命令) 在发布包根目录(见 4.1)下**复制整行**执行即可(与 `README.md` §4 相同;不写占位符:组织/电梯 URL 与访客号段已由交付对齐): ```bash python3 -m pip install -q -r python/requirements-min.txt && python3 python/quick_verify_visitor_floor_policy.py --mode noauth-probe --org-base-url "http://10.0.22.207:8089" --elevator-base-url "http://10.0.22.207:16112" --use-preset-cases --visitor-person-ids "$(python3 -c 'print(",".join(str(9199000100000000000+i) for i in range(1,26)))')" --probe-with-businessid --batch-output-summary "batch-preset-static-$(date +%Y%m%d-%H%M%S).json" ``` 结果见 `report/batch-preset-static-*.json`。 ### 4.0.1 执行后数据库核验(必须) 在完成 §4.0 且已拿到批量 JSON 后,于**与本环境电梯服务写入同一套库的** MySQL(`cw-elevator-application`)执行: `sql/标准批量25访客-执行后核验.sql` **如何对照判断「是否跑成功」** 1. 打开本轮 `report/batch-preset-static-*.json`,对每条样本看 `steps.add_visitor.business_ok`、`derived.floor_count`、`grade`。 2. 对 **`add_visitor` 业务成功** 且 `passRule/image` HTTP 大体正常的样本,在同一库中期望:查询 **A** 中该行访客的 **`active_row_count` ≥ 1**(租户策略或写库链路正常时,`person_delete=0` 的规则行应与接口返回楼层有对应);**全部为 0** 则重点排查写库延迟、租户/访客 ID 不真实、或网关虽 200 实际未打到目标实例。 3. 查询 **B** 与 JSON 内 `derived.floors[].zoneId` 做逐项比对;若库中 `person_delete=1` 的历史行较多,结合 `last_update_time` 看是否为本次执行产生的新生效行。 4. 若访客号段与本包约定不一致(非 `919900…`),请改用 `sql/人工核查最终楼层结果.sql`,将 `IN (...)` 换为当天 JSON 中全部 `resolved_visitor_person_id`。 ### 4.1 进入发布目录 ```bash cd docs/testing/release-visitor-noauth-verify-v20260430 ``` ### 4.2 样本1(广发基金基线)执行 本节「黄平 + 蒙海文」样本用于:**无鉴权下探针是否可走通**,以及 **`passRule/image` 返回是否与租户策略语义一致**。它**不是用来**证明「在本次执行中产出了全新访客主数据」——`add/visitor` 传入的是已在组织/电梯侧建档的访客 `personId` 时,写库常为**续约/补齐规则**,`image_rule_ref` 里的行常与**历史登记**混在一起。 若验收目标是「必须先有真实新增访客,再验证派梯」,请: - **优先**:走 **§4.0** 约定号段 **`9199000100000000001`~`…0025`** 的批量预置链路(租户内已预置对应用人,`image_rule_ref` 证据与 JSON 对齐); - 或:业务流程上**新开一名访客**,再将其 `visitorPersonId` 交给本脚本;查库时对 `last_update_time` 与脚本 JSON 顶层 **`started_at`** 做对时(仅能辅助说明「本轮是否写过」)。 ```bash python3 python/quick_verify_visitor_floor_policy.py \ --mode noauth-probe \ --org-base-url "http://10.0.22.207:8089" \ --elevator-base-url "http://10.0.22.207:16112" \ --business-id "2524639890ba4f2cba9ba1a4eeaa4015" \ --meng-person-id "964454497399468032" \ --visitor-person-id "1102270499947507712" \ --probe-with-businessid ``` ### 4.3 样本2(其他公司多部门)执行 在与**当前验证目标环境一致**的 MySQL 上执行 `sql/批量样本筛选-多公司多部门.sql`(或等价查询),导出被访人到 `sql/batch_cases.csv`。**禁止**用开发环境数据库导出样本却去打生产 HTTP。**开发环境快照仅可用于开发联调**,生产走查必须使用生产侧数据或手写/审批过的样本 CSV。 ```bash python3 python/quick_verify_visitor_floor_policy.py \ --mode noauth-probe \ --org-base-url "http://10.0.22.207:8089" \ --elevator-base-url "http://10.0.22.207:16112" \ --batch-input-csv "sql/batch_cases.csv" \ --visitor-person-ids "<访客ID1>,<访客ID2>,<访客ID3>" \ --visitor-names "黄志平A,黄志平B,黄志平C" \ --probe-with-businessid ``` 建议最少覆盖: - 3 个不同公司; - 每公司 2 个不同部门被访人。 若已导出 `docs/testing/_cw_is_person__202604302030.csv`,可直接自动筛选(排除广发基金): ```bash python3 python/quick_verify_visitor_floor_policy.py \ --mode noauth-probe \ --org-base-url "http://10.0.22.207:8089" \ --elevator-base-url "http://10.0.22.207:16112" \ --batch-source-person-csv "../_cw_is_person__202604302030.csv" \ --exclude-business-ids "2524639890ba4f2cba9ba1a4eeaa4015" \ --sample-companies 3 \ --sample-persons-per-company 2 \ --visitor-person-ids "<访客ID1>,<访客ID2>,<访客ID3>" \ --visitor-names "黄志平A,黄志平B,黄志平C" \ --probe-with-businessid ``` 说明: - 自动筛选依赖列:`BUSINESS_ID`,`ID`,`NAME`;若存在 **`IS_DEL`**,脚本会**跳过已删除行**(`IS_DEL≠0` 或与 `true`/`1` 等价)。 - 该 CSV 若无标准部门列,汇总中 `department` 将为空。 ### 4.4 结果判定 脚本 `noauth-probe` 对每条样本计算 `grade`(单样本写入 `quick-verify-*.json`;批量写入每条 `results[]`): - `grade=high_risk`:任一步均未出现 401/403,且 **`add/visitor` 的 HTTP 成功(<300)且接口业务码判定为成功**(`business_ok`),判定高风险放开(安全问题成立)。若仅 HTTP 200 但业务失败,归为 `needs_review`,不是 `high_risk`。 - `grade=expected_block`:**人员详情、`add/visitor`、`passRule/image` 任一步**出现 401/403,视为无鉴权被拦截,符合安全预期。 - `grade=needs_review`:未出现 401/403,但未达到上述「放行且业务成功」条件(例如网关超时、业务码失败等),需人工复核。 - `grade=failed`(批量中单条可出现):访客 `personId` 无法解析且无内置兜底等情况,脚本未完成调链;不按上述安全三档解释,需先看 `summary`/JSON 报错原因。 ### 4.5 汇总输出(必须) 最终按样本输出表格(建议 CSV/Markdown;字段可从批量 JSON **`results[]`** 各条中取): - 公司:`sample.company` - 部门:`sample.department` - 被访人 `personId`:`args.meng_person_id` - 访客 `personId`:`args.resolved_visitor_person_id` - **`add/visitor` 业务码**:`steps.add_visitor.business_code`(及 `http_status`) - **`passRule/image`**:`steps.passrule_image` 内的 `business_code` / `http_status` - 楼层数量:`derived.floor_count` - 楼层清单:`derived.floors`(元素含 `zoneId`/`zoneName`) - 安全分档:`grade`、`summary` 控制台会摘要打印 `company/department`、`addCode`、`floorCount`;完整以 JSON 为准。 批量汇总文件:**默认** `report/batch-summary.json`;若使用了 `--batch-output-summary`(如 §4.0 的 `batch-preset-static-*.json`),则路径为 **`report/` + 传入文件名**。 ### 4.6 人工 SQL 核查最终结果(最后一步) - §4.0 固定 25 号段:**优先**执行 `sql/标准批量25访客-执行后核验.sql`。 - 其它访客清单或单笔核对:执行 `sql/人工核查最终楼层结果.sql`,自行替换 `IN (...)`。 核查要点: - 按本次访客ID集合过滤,确认 `person_delete=0` 的有效规则; - 对比 `zone_id` 与脚本输出楼层清单; - 如存在历史残留,结合 `create_time` / **`last_update_time`**(`image_rule_ref`)判定最新记录。 ### 4.7 业务侧整改后关键日志检查点 本版整改聚焦业务策略链路,不调整鉴权逻辑。应用日志需出现: - 策略决策日志(`PersonRuleServiceImpl`)含字段: - `policyDecision`、`hostFloorSize`、`allowFloorSize`、`effectiveFloorSize`(有一条覆盖生效日志中占位名为 `effectiveSize`,与同次决策中的楼层数量一致)、`policyId`、`policyVersion` 失败路径上的告警亦多为 `WARN`/`INFO`(如「访客派梯楼层决策失败-…」「allow_zone_ids JSON 无效」),便于在无 DEBUG 前提下排查。**是否仍存在「仅为探针、且仍为 DEBUG」的日志行,请以当前发布包镜像实际 `logback` 与源码为准逐项核对**。 ## 5. 证据留档 至少归档以下内容: 1. 执行命令 2. 脚本输出摘要(控制台) 3. 生成的 JSON:**单样本** `report/quick-verify-*.json`;**标准批量** `report/batch-preset-static-*.json` 或其他 `--batch-output-summary` 指定名 4. **`sql/标准批量25访客-执行后核验.sql`(或等价)查询导出**与其它 SQL 核验结果一并留档 5. 关键接口返回截图/日志