如何使用HTTPRequestMessage添加SOAP身份验证头?

8

这就是标题应该看起来的样子

<soap:Header>
   <AuthenticationHeader>
     <UserName>string</UserName>
     <Password>string</Password>
   </AuthenticationHeader>
 </soap:Header>

以下是我尝试过的方法:

string username = "TheUserName";
string password = "ThePassword";

HttpRequestMessage requestMessage = new HttpRequestMessage(method, uri);
requestMessage.Headers.Add("UserName", username);
requestMessage.Headers.Add("Password", password);

也许我需要设置授权头部?
requestMessage.Headers.Authorization = ??

我觉得我需要“构建”那个AuthenticationHeader元素,但是我不确定该如何实现。有什么建议吗?

编辑:完整的SOAP信封

?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Header>
    <AuthenticationHeader xmlns="http://www.test.com/testing/Security">
      <UserName>string</UserName>
      <Password>string</Password>
    </AuthenticationHeader>
  </soap:Header>
  <soap:Body>
    <GetMeSomething xmlns="http://www.test.com/testing/WorkFileCatalog">
      <Param1>string</Param1>
      <Param2>string</Param2>
      <XMLRetMess>string</XMLRetMess>
    </GetMeSomething>
  </soap:Body>
</soap:Envelope>

1
通常的做法是将用户名和密码附加到用于发送请求的对象上,例如 yourObject.Credentials = new System.Net.NetworkCredential(username, password); 你试过这样做吗? - balexandre
我不确定你所说的“yourObject”是什么意思。我正在尝试使用“HttpClient”。实际上,我创建了一个服务引用,这简化了很多事情,但我应该能够改用“HttpClient”,并只使用服务引用来处理请求和响应对象。我只是在语法方面遇到了一些麻烦,因为我不知道所有这些对象如何转换为标记。 - Pittfall
如果那不行的话,你真的需要分两步发送,先发送认证,等待回复,然后再发送正常请求(通常带有从认证获取的响应标头)... - balexandre
2
@Pittfall 你知道SOAP头是消息信封的一部分,作为请求正文的一部分发送,并与HTTP请求授权头无关吗? - Nkosi
@Nkosi 那个SOAP信封就是请求。我想更清楚地表达一下,我有点想知道是否可以在不手动解析和替换的情况下添加该标头。如果这是唯一的解决方案,那么我会接受它,但是我之前调用过另一个服务,没有标头,只有SOAP正文,我不需要手动放入任何XML。我使用FormUrlEncodedContent对象填充了我的requestMessage.Content,并将其发送出去。如果需要,我可以进一步详细说明该示例。我认为我可以以同样的方式处理标头。 - Pittfall
显示剩余10条评论
2个回答

1

根据提供的OP,下面的单元测试是作为概念验证的一部分完成的,以展示如何填充消息头并创建请求。

[TestClass]
public class SOAP_UnitTests {
    private HttpMethod method;
    private string uri;
    private string action;

    [TestMethod]
    public void _Add_SOAP_Auth_Header_Details_With_HttpRequestMessage() {
        string username = "TheUserName";
        string password = "ThePassword";

        var xml = ConstructSoapEnvelope();
        var doc = XDocument.Parse(xml);
        var authHeader = doc.Descendants("{http://www.test.com/testing/Security}AuthenticationHeader").FirstOrDefault();
        if (authHeader != null) {
            authHeader.Element(authHeader.GetDefaultNamespace() + "UserName").Value = username;
            authHeader.Element(authHeader.GetDefaultNamespace() + "Password").Value = password;
        }
        string envelope = doc.ToString();

        var request = CreateRequest(method, uri, action, doc);
        request.Content = new StringContent(envelope, Encoding.UTF8, "text/xml");

        //request is now ready to be sent via HttpClient
        //client.SendAsync(request);
    }

    private static HttpRequestMessage CreateRequest(HttpMethod method, string url, string action, XDocument soapEnvelopeXml) {
        var request = new HttpRequestMessage(method: method, requestUri: url);
        request.Headers.Add("SOAPAction", action);
        request.Headers.Add("ContentType", "text/xml;charset=\"utf-8\"");
        request.Headers.Add("Accept", "text/xml");
        request.Content = new StringContent(soapEnvelopeXml.ToString(), Encoding.UTF8, "text/xml"); ;
        return request;
    }

    private string ConstructSoapEnvelope() {
        var message = @"<?xml version='1.0' encoding='utf-8'?>
<soap:Envelope xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:xsd='http://www.w3.org/2001/XMLSchema' xmlns:soap='http://schemas.xmlsoap.org/soap/envelope/'>
  <soap:Header>
    <AuthenticationHeader xmlns='http://www.test.com/testing/Security'>
      <UserName>string</UserName>
      <Password>string</Password>
    </AuthenticationHeader>
  </soap:Header>
  <soap:Body>
    <GetMeSomething xmlns='http://www.test.com/testing/WorkFileCatalog'>
      <Param1>string</Param1>
      <Param2>string</Param2>
      <XMLRetMess>string</XMLRetMess>
    </GetMeSomething>
  </soap:Body>
</soap:Envelope>
";
        return message;
    }
}

-1
如果您正在使用 HttpClient 进行 POST 请求,那么您应该构建完整的 XML 请求。
换句话说,您需要构建包含所有元素的完整 Soap XML。
string requestXml = your actual full soap xml
string result = HttpClient.Post ( your actual xml )

请删除这个答案,我不是要冒犯你,但这是一个hack而不是我想要的。它可能有效,但我想使用.NET提供的对象。如果协议发生变化,任何类似于这样的操作都会失败。 - Pittfall
嗯...这是一种非常有效的方法,适用于非常简单的Soap请求。我们使用它并且到目前为止很满意。在我看来,这完全取决于上下文。 - Subbu
我并不是说它不能工作,只是说这不是一个好的解决方案。让我举个例子。想象一下使用 string s = ""string s = string.Empty。两种方法都是有效的,但如果空字符串的值从 "" 更改为 "|"string.Empty 将被更新。现在这个例子可能基于永远不会改变的东西,但我希望你能理解我的意思。 - Pittfall

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接