OPA不原生支持xml解析,必须在接入层将XML转为jsON后才能策略校验;转换需保留层级与数组语义,失败时返回400,严禁传原始XML;策略基于转换后的json结构编写,并确保字段路径与转换逻辑严格对齐。

OPA 本身不原生解析 XML,所以不能直接对 XML 内容做策略判断——你得先让服务把 XML 解析成 JSON(或结构化数据),再把结果传给 OPA;否则 opa eval 或 data.system 规则里根本拿不到 /order/amount 这样的路径。
XML 必须在接入层转成 JSON 才能被 OPA 处理
OPA 的输入是纯 JSON,没有 XML 解析器,也不支持 XPath。常见错误是试图在 rego 里用正则去“匹配 XML 字符串”,这既不可靠(命名空间、缩进、CDATA、属性顺序都会破坏匹配),也无法做语义校验(比如数值范围、必填字段、枚举值)。
- 推荐在 API 网关(如 Envoy + wasm)、后端服务(如 python flask/fastapi、go gin)或专用转换中间件中,用标准库(如 Python
xml.etree.ElementTree或 Goencoding/xml)将 XML body 解析为 JSON - 转换时注意保留层级和数组语义:例如多个
应转为 JSON 数组而非单个对象 - 转换失败(格式错误、非法字符、超大 payload)必须拦截并返回 400,**绝不能把原始 XML 字符串当 input 传给 OPA**
定义基于 XML 结构的访问策略(以订单上传为例)
假设上传的 XML 经转换后变成如下 JSON:
{ "order": { "id": "ORD-2024-789", "customer_id": "CUST-123", "amount": 299.99, "currency": "USD", "items": [ { "sku": "A123", "qty": 2 }, { "sku": "B456", "qty": 1 } ] } }
对应 rego 策略可写为:
package xml_upload default allow = false allow { input.order.id input.order.customer_id input.order.amount > 0 input.order.currency == "USD" count(input.order.items) >= 1 some i input.order.items[i].qty > 0 }
-
input.order.id这类路径依赖于你实际的 JSON 结构,务必与转换逻辑严格对齐 - 若 XML 允许空元素(如
),转换后可能是"discount": NULL或缺失字段,需在 rego 中用input.order.discount != null或not is_null(input.order.discount)显式判断 - 敏感字段(如
customer_id)可结合user.groups做 RBAC:比如只允许"finance"组上传金额 >1000 的订单
如何把 XML 转换逻辑和 OPA 集成到真实接口
典型链路是:http POST XML → 网关/服务解析为 JSON → 注入用户身份(JWT / header)→ 调用 OPA /v1/data/xml_upload/allow → 拒绝或放行。
- 不要在 rego 里调外部服务查用户权限;把
user.roles、user.tenant_id等作为 top-level 字段随 JSON input 一起传入 - 如果 XML 含 Base64 编码的二进制附件(如 pdf),转换时应剥离或仅校验其 hash/MIME,避免 OPA 输入过大(OPA 推荐单次 input
- 使用
opa build打包策略时,确保package xml_upload和 HTTP 请求路径一致,否则POST /v1/data/xml_upload/allow会 404
真正卡住人的地方不是 rego 语法,而是 XML 到 JSON 的映射是否保真、是否覆盖了所有边缘 case(比如空标签、默认命名空间、混合内容)。哪怕策略写得再严,解析一错,就等于裸奔。