签署文档时使用的 xslt 转换与计算签名时如何选择源 XML 中的节点有关。
Dave的这个问题/答案与使用xpath2 对 XML 文档的部分进行签名有关。这个答案中 Sean Mullans 的帖子的链接表明xpath2 更适合签署文档的某些部分,因为 xpath 表达式的评估是按节点完成的。
因此,基于sun dsig 示例,您可以使用以下方法替换参考创建:
List<XPathType> xpaths = new ArrayList<XPathType>();
xpaths.add(new XPathType("//r1/user", XPathType.Filter.INTERSECT));
Reference ref = fac.newReference
("", fac.newDigestMethod(DigestMethod.SHA1, null),
Collections.singletonList
(fac.newTransform(Transform.XPATH2,
new XPathFilter2ParameterSpec(xpaths))),
null, null);
这允许//r1/user受到签名保护,而文档的其余部分可以被更改。
xpath/xpath2 选择的问题是可以为/some/node/that/does/not/exist生成签名。您修改测试文档并确保签名按您期望的方式工作是正确的。
您可以在测试程序中通过生成签名然后在验证之前篡改 xml 节点来测试文档:
NodeList nlt = doc.getElementsByTagName("user");
nlt.item(0).getFirstChild().setTextContent("Something else");
xpath 选择器的更可靠替代方法可能是将 ID 放在您希望签名的 xml 文档元素上,例如:
<r1>
<user id="sign1">asd</user>
<person>ghi</person>
</r1>
然后将此 ID 引用为封装传输的第一个参数中的 URI:
Reference ref = fac.newReference
("#sign1", fac.newDigestMethod(DigestMethod.SHA1, null),
Collections.singletonList
(fac.newTransform(Transform.ENVELOPED,(TransformParameterSpec) null)),
null, null);
对于输出,签名操作将一个新的 Signature 元素添加到您在内存中加载的 DOM。您可以通过像这样转换输出来流式传输输出:
TransformerFactory tf = TransformerFactory.newInstance();
Transformer trans = tf.newTransformer();
trans.setOutputProperty(OutputKeys.INDENT, "yes");
trans.transform(new DOMSource(doc), new StreamResult(System.out));