[英]Send SOAP request with PFX Certificate via C#
我需要使用 PFX 证书调用 SOAP Web 服务。 我正在尝试在 .NET 4.7.2 Console App 中编写它。 下面是我写的。
public async Task<string> CreateSoapEnvelope()
{
string soapString = @"<?xml version=""1.0"" encoding=""utf-8""?>
<soapenv:Envelope xmlns:soapenv=""http://schemas.xmlsoap.org/soap/envelope/"" xmlns:b2b=""Some_URL"">
<soapenv:Header/>
<soapenv:Body>
SOAP_BODY
</soapenv:Body>
</soapenv:Envelope>";
HttpResponseMessage response = await PostXmlRequest("CLIENT_URL", soapString);
string content = await response.Content.ReadAsStringAsync();
return content;
}
public static async Task<HttpResponseMessage> PostXmlRequest(string baseUrl, string xmlString)
{
try
{
// Create HttpClientHandler instance
var handler = new HttpClientHandler();
// Add the certificate
var certPath = @"PathToCertificate"; // Path to PFX fle
var cert = new X509Certificate2(certPath, "Password");
handler.ClientCertificates.Add(cert);
using (var httpClient = new HttpClient(handler))
{
var httpContent = new StringContent(xmlString, Encoding.UTF8, "text/xml");
httpContent.Headers.Add("SOAPAction", "");
return await httpClient.PostAsync(baseUrl, httpContent);
}
}catch(Exception ex)
{
}
return null;
}
现在,当我调用 CreateSoapEnvelope() 时,它总是出错并显示 InternalServerError。
下面是我收到的故障字符串。
<faultstring>No signature in message! (from client). Rejected by filter; SOAP fault sent.Rejected by filter; SOAP fault sent. </faultstring><detail><service_error_message>No signature in message!</service_error_message>
我做错了什么吗? 我对 SOAP 和 PFX 完全陌生。 任何帮助表示赞赏。
正如@bartonjs 的其中一条评论中提到的,问题是该服务期望我的消息得到签名。 我最终做的是将签名显式添加到消息中并且它起作用了。 我的印象是客户端证书本身应该没问题,但事实并非如此。 我仍在寻找更清洁的解决方案,但现在以下有效。
public static async Task<string> SignXml(XmlDocument document, X509Certificate2 cert)
{
return await Task.Run(() =>
{
CryptoConfig.AddAlgorithm(typeof(RSAPKCS1SHA256SignatureDescription), "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256");
// Export private key from cert.PrivateKey and import into a PROV_RSA_AES provider:
var exportedKeyMaterial = cert.PrivateKey.ToXmlString( /* includePrivateParameters = */ true);
var key = new RSACryptoServiceProvider(new CspParameters(24 /* PROV_RSA_AES */));
key.PersistKeyInCsp = false;
key.FromXmlString(exportedKeyMaterial);
SignedXml signedXml = new SignedXml(document);
signedXml.SigningKey = key;
signedXml.SignedInfo.SignatureMethod = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256";
//
// Add a signing reference, the uri is empty and so the whole document
// is signed.
Reference reference = new Reference();
reference.AddTransform(new XmlDsigEnvelopedSignatureTransform());
reference.AddTransform(new XmlDsigExcC14NTransform());
reference.Uri = "";
signedXml.AddReference(reference);
// Add the certificate as key info, because of this the certificate
// with the public key will be added in the signature part.
KeyInfo keyInfo = new KeyInfo();
keyInfo.AddClause(new KeyInfoX509Data(cert));
signedXml.KeyInfo = keyInfo;
// Compute the signature.
signedXml.ComputeSignature();
// Get the XML representation of the signature and save
// it to an XmlElement object.
XmlElement xmlDigitalSignature = signedXml.GetXml();
//get the SOAP-SEC header and add our signature to it
var soapSecurityList = document.GetElementsByTagName("Header", "http://schemas.xmlsoap.org/soap/envelope/");
if (soapSecurityList.Count == 0)
{
throw new Exception("Could not find SOAP-SEC header!");
}
var soapSecurity = soapSecurityList.Item(0);
soapSecurity.AppendChild(xmlDigitalSignature);
return document.OuterXml;
});
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.