使用 JavaScript 和 jQuery 修改命名空间 XML
Modify namespaced XML using JavaScript with jQuery
我有一个命名空间 XML 文档必须使用特殊的浏览器插件签名。
这里是平安密码,即签文件:
var oCertificate = GetCertificateBySubjectName(certificateName);
var token = oCertificate.Export(CADESCOM_ENCODE_BASE64);
var element, xmlDoc;
xmlDoc = $.parseXML(doc.toString());
element = $(xmlDoc).find("o\:BinarySecurityToken");
element.text(token);
var xmlString = undefined;
if (window.ActiveXObject) {
xmlString = xmlDoc[0];
}
if (xmlString === undefined) {
var oSerializer = new XMLSerializer();
xmlString = (new XMLSerializer()).serializeToString(xmlDoc);
}
var doc = SignCreate(oCertificate, xmlString);
其中 doc 是包含 XML.
的字符串
这里是平安XML必须要签的东西:
<s:Header>
<o:Security s:mustUnderstand="1" xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" s:actor="http://smev.gosuslugi.ru/actors/smev">
<o:BinarySecurityToken u:Id="uuid-ee82d445-758b-42cb-996c-666b74b60022-2" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary"/>
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
<SignedInfo>
<CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
<SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#gostr34102001-gostr3411" />
<Reference URI="#_1">
<Transforms>
<Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#gostr3411" />
<DigestValue/>
</Reference>
</SignedInfo>
<SignatureValue/>
<KeyInfo>
<o:SecurityTokenReference>
<o:Reference ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" URI="#uuid-ee82d445-758b-42cb-996c-666b74b60022-2" />
</o:SecurityTokenReference>
</KeyInfo>
</Signature>
</o:Security>
</s:Header>
文件的签署是这样进行的。使用
xmlDoc = $.parseXML(message.toString());
element = $(xmlDoc).find("o\:BinarySecurityToken");
element.text(token);
我将证书中的令牌放入 <o:BinarySecurityToken>
然后将其转换回字符串并发送给 sign.
在这个步骤中我得到了:
<o:BinarySecurityToken u:Id="uuid-ee82d445-758b-42cb-996c-666b74b60022-2" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">!!TOKEN!!</o:BinarySecurityToken>
然后
<o:BinarySecurityToken u:Id="uuid-ee82d445-758b-42cb-996c-666b74b60022-2" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">!!!TOKEN!!!</o:BinarySecurityToken>
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
<SignedInfo>
<CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
<SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#gostr34102001-gostr3411"/>
<Reference URI="#_1">
<Transforms>
<Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#gostr3411"/>
<DigestValue>!!!SIGNATURE DIGEST VALUE!!!</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>!!!SIGNATURE!!!</SignatureValue>
一切在 FireFox 和 (!)IE 中运行良好,但在 Google Chrome 中不起作用。在 Chrome 将令牌放入的代码中,将其留空,所有其他方法均无效。
所以,我的问题是:我应该怎么做才能解决这个问题?我尝试使用 https://github.com/rfk/jquery-xmlns 来赋予 jQuery 一些使用命名空间 XML 的能力,但是这个库在我的代码中没有 运行。
提前致谢。
P.S。我使用 jQuery 1.10.2
jQuery 不支持命名空间,只支持节点名称中的冒号。我无法让 jquery-xmlns 插件与当前的 jQuery 版本一起使用。
新的Document.querySelector()
和Document.querySelectorAll()
方法也不支持命名空间。
但是 Document.evaluate()
和 Document
本身就可以。它们允许使用 XPath。除 IE 之外的所有现代浏览器都支持 Document.evaluate()
。对于 IE,可以使用 JavaScript library 将方法添加到文档对象。
var dom = (new DOMParser()).parseFromString(xml, 'application/xml');
var resolver = {
namespaces : {
'o' : 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd'
},
lookupNamespaceURI : function(prefix) {
if (prefix == '') {
return null;
}
return this.namespaces[prefix] || null;
}
};
var node = dom.evaluate(
'//o:BinarySecurityToken',
dom,
resolver,
XPathResult.FIRST_ORDERED_NODE_TYPE,
null
).singleNodeValue;
node.appendChild(dom.createTextNode('TOKEN_TEXT'));
document.querySelector('#output').textContent = (new XMLSerializer()).serializeToString(dom);
演示:http://jsfiddle.net/mec2qxLa/2/
要使其与 IE 兼容,您需要加载 xpath.js。它将评估方法附加到 document
对象。对于新的 Document
个实例,您可以从那里获取它。它不发布 XPathResult
对象,但它定义了一个提供它的 xpath
对象。
var dom = (new DOMParser()).parseFromString(xml, 'application/xml');
if (!dom.evaluate && document.evaluate) {
dom.evaluate = document.evaluate;
if (typeof XPathResult == 'undefined') {
XPathResult = xpath.XPathResult;
}
}
...
我有一个命名空间 XML 文档必须使用特殊的浏览器插件签名。
这里是平安密码,即签文件:
var oCertificate = GetCertificateBySubjectName(certificateName);
var token = oCertificate.Export(CADESCOM_ENCODE_BASE64);
var element, xmlDoc;
xmlDoc = $.parseXML(doc.toString());
element = $(xmlDoc).find("o\:BinarySecurityToken");
element.text(token);
var xmlString = undefined;
if (window.ActiveXObject) {
xmlString = xmlDoc[0];
}
if (xmlString === undefined) {
var oSerializer = new XMLSerializer();
xmlString = (new XMLSerializer()).serializeToString(xmlDoc);
}
var doc = SignCreate(oCertificate, xmlString);
其中 doc 是包含 XML.
的字符串这里是平安XML必须要签的东西:
<s:Header>
<o:Security s:mustUnderstand="1" xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" s:actor="http://smev.gosuslugi.ru/actors/smev">
<o:BinarySecurityToken u:Id="uuid-ee82d445-758b-42cb-996c-666b74b60022-2" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary"/>
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
<SignedInfo>
<CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
<SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#gostr34102001-gostr3411" />
<Reference URI="#_1">
<Transforms>
<Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#gostr3411" />
<DigestValue/>
</Reference>
</SignedInfo>
<SignatureValue/>
<KeyInfo>
<o:SecurityTokenReference>
<o:Reference ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" URI="#uuid-ee82d445-758b-42cb-996c-666b74b60022-2" />
</o:SecurityTokenReference>
</KeyInfo>
</Signature>
</o:Security>
</s:Header>
文件的签署是这样进行的。使用
xmlDoc = $.parseXML(message.toString());
element = $(xmlDoc).find("o\:BinarySecurityToken");
element.text(token);
我将证书中的令牌放入 <o:BinarySecurityToken>
然后将其转换回字符串并发送给 sign.
在这个步骤中我得到了:
<o:BinarySecurityToken u:Id="uuid-ee82d445-758b-42cb-996c-666b74b60022-2" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">!!TOKEN!!</o:BinarySecurityToken>
然后
<o:BinarySecurityToken u:Id="uuid-ee82d445-758b-42cb-996c-666b74b60022-2" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">!!!TOKEN!!!</o:BinarySecurityToken>
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
<SignedInfo>
<CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
<SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#gostr34102001-gostr3411"/>
<Reference URI="#_1">
<Transforms>
<Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#gostr3411"/>
<DigestValue>!!!SIGNATURE DIGEST VALUE!!!</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>!!!SIGNATURE!!!</SignatureValue>
一切在 FireFox 和 (!)IE 中运行良好,但在 Google Chrome 中不起作用。在 Chrome 将令牌放入的代码中,将其留空,所有其他方法均无效。
所以,我的问题是:我应该怎么做才能解决这个问题?我尝试使用 https://github.com/rfk/jquery-xmlns 来赋予 jQuery 一些使用命名空间 XML 的能力,但是这个库在我的代码中没有 运行。
提前致谢。
P.S。我使用 jQuery 1.10.2
jQuery 不支持命名空间,只支持节点名称中的冒号。我无法让 jquery-xmlns 插件与当前的 jQuery 版本一起使用。
新的Document.querySelector()
和Document.querySelectorAll()
方法也不支持命名空间。
但是 Document.evaluate()
和 Document
本身就可以。它们允许使用 XPath。除 IE 之外的所有现代浏览器都支持 Document.evaluate()
。对于 IE,可以使用 JavaScript library 将方法添加到文档对象。
var dom = (new DOMParser()).parseFromString(xml, 'application/xml');
var resolver = {
namespaces : {
'o' : 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd'
},
lookupNamespaceURI : function(prefix) {
if (prefix == '') {
return null;
}
return this.namespaces[prefix] || null;
}
};
var node = dom.evaluate(
'//o:BinarySecurityToken',
dom,
resolver,
XPathResult.FIRST_ORDERED_NODE_TYPE,
null
).singleNodeValue;
node.appendChild(dom.createTextNode('TOKEN_TEXT'));
document.querySelector('#output').textContent = (new XMLSerializer()).serializeToString(dom);
演示:http://jsfiddle.net/mec2qxLa/2/
要使其与 IE 兼容,您需要加载 xpath.js。它将评估方法附加到 document
对象。对于新的 Document
个实例,您可以从那里获取它。它不发布 XPathResult
对象,但它定义了一个提供它的 xpath
对象。
var dom = (new DOMParser()).parseFromString(xml, 'application/xml');
if (!dom.evaluate && document.evaluate) {
dom.evaluate = document.evaluate;
if (typeof XPathResult == 'undefined') {
XPathResult = xpath.XPathResult;
}
}
...