5

我正在为某些 STS 服务构建一个客户端,并且现在我正在尝试向 WCF 消息添加一个标头。在我对 RequestSecurityToken 的调用中,我必须包含一个 UsernameToken。

我不确定如何做到这一点。目前我定义了一个端点行为和一个消息检查器(花了我足够长的时间来发现这些......)。在后者的 BeforeSendRequest() 中,我创建了一个派生自 MessageHeader 的自定义类“Security”的对象。安全性包括 UsernameToken 的一个实例。

public class MessageInspector : IClientMessageInspector {

 public object BeforeSendRequest(ref Message request, IClientChannel channel) {
    Security uns = new Security();
    uns.UsernameToken = new UsernameToken();

    // ...

    var Header = new MessageHeader<Security>(uns);
    var untyped = Header.GetUntypedHeader("Security", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
    request.Headers.Add(untyped);
    return null;
 }
}

public class Security : MessageHeader {
 public UsernameToken UsernameToken = new UsernameToken();

 public override string Name {
    get { return "Security"; }
 }

 public override string Namespace {
    get { return "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"; }
 }
}

public class UsernameToken {
 public String Username = "";
 public Password Password = new Password();
}

这是正在序列化的内容

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  <s:Header>
    <Action s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">urn:RequestSecurityToken</Action>
    <Security xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
      <UsernameToken xmlns="http://schemas.datacontract.org/2004/07/Tarifrechner.Kfz">
        <Password>
          <Type>http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText</Type>
          <password>******</password>
        </Password>
        <Username>******</Username>
      </UsernameToken>
    </Security>
  </s:Header>
  <s:Body />
</s:Envelope>

特别是 UsernameToken 的命名空间似乎是错误的。我知道它来自数据合同序列化,但我需要一个不同的命名空间。

这就是我希望序列化数据的样子

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="...">
  <soap:Header>
    <Security xmlns:q1="http://www.bipro.net/namespace" xsi:type="q1:UserNameSecurity" 
          xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
      <UsernameToken>
        <Username>******</Username>
        <Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">******</Password>
      </UsernameToken>
    </Security>
    <wsa:Action>urn:RequestSecurityToken</wsa:Action>
    <wsse:Security>
      <wsu:Timestamp wsu:Id="Timestamp-b9dd599d-5901-451d-8321-6a309091f273">
        <wsu:Created>2012-03-11T16:02:56Z</wsu:Created>
        <wsu:Expires>2012-03-11T16:07:56Z</wsu:Expires>
      </wsu:Timestamp>
    </wsse:Security>
  </soap:Header>
  <soap:Body>
    <RequestSecurityToken xmlns="http://schemas.xmlsoap.org/ws/2005/02/trust">
      <TokenType>http://schemas.xmlsoap.org/ws/2005/02/sc/sct</TokenType>
      <RequestType>
        http://schemas.xmlsoap.org/ws/2005/02/trust/Issue
      </RequestType>
    </RequestSecurityToken>
  </soap:Body>
</soap:Envelope>

我的方法对吗?以及如何操作诸如标题详细信息的名称空间或数据是否被序列化为属性或元素之类的东西?

更新


正如 Ladislav 已经指出的那样,我不必自己实现像 UsernameToken 这样的类。我这样做只是因为我对 WCF 的了解非常有限。

到现在为止,我发现 WS2007HttpBinding 配置为使用 SecurityMode.TransportWithMessageCredential 并且将 EstablishSecurityContext 设置为 false 几乎可以生成我正在寻找的 XML。我怎么会知道的?

但是还有一个问题:我的请求有一个空的 body 元素,我想要生成的请求在 body 元素内具有一个 RequestSecurityToken 元素。有谁知道,我怎么能做到这一点?

使用 EstablishSecurityContext = true 有帮助,但同时将我的 Soap-Action 从所需的“urn:RequestSecurityToken”更改为不工作的“http://docs.oasis-open.org/ws-sx/ws-trust/200512 /RST/SCT”。


我很感激任何答案!

非常感谢!

比约恩

4

2 回答 2

1

另一种方法是为您的请求定义一个MessageContract类型,它允许您定义在 SOAP 消息的标头和正文中显示的内容并调整使用的名称空间。例如,考虑以下服务定义:

[ServiceContract]
    public interface IMyService
    {
        [OperationContract]
        MyResponse DoSomething(MyRequest request);
    }

    public class MyService : IMyService
    {
        public MyResponse DoSomething(MyRequest request)
        {
            return new MyResponse()
            {
                Details = "Service did something awesome.",
                Timestamp = DateTime.Now
            };
        }
    }

    [MessageContract(IsWrapped = true, WrapperNamespace = "http://myservice/messages/")]
    public class MyRequest
    {
        [MessageHeader(Namespace = "http://myservice/security")]
        public string TokenThingy
        {
            get;
            set;
        }
    }

    [MessageContract(IsWrapped = true, WrapperNamespace = "http://myservice/messages")]
    public class MyResponse
    {
        [MessageBodyMember]
        public string Details
        {
            get;
            set;
        }

        [MessageBodyMember]
        public DateTime Timestamp
        {
            get;
            set;
        }
    }

发送请求会生成以下 SOAP:

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  <s:Header>
    <Action s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">http://tempuri.org/IMyService/DoSomething</Action>
    <h:TokenThingy xmlns:h="http://myservice/security">fda</h:TokenThingy>
  </s:Header>
  <s:Body>
    <MyRequest xmlns="http://myservice/messages/" />
  </s:Body>
</s:Envelope>

该服务的响应如下所示:

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  <s:Header />
  <s:Body>
    <MyResponse xmlns="http://myservice/messages">
      <Details xmlns="http://tempuri.org/">Service did something awesome.</Details>
      <Timestamp xmlns="http://tempuri.org/">2012-05-04T17:04:36.5980424-04:00</Timestamp>
    </MyResponse>
  </s:Body>
</s:Envelope>
于 2012-05-04T21:12:13.343 回答
0

有几种不同的方法可以将标题添加到消息中,具体取决于您需要如何控制标题内容以及需要在何处插入标题。

在您的应用程序代码中,您可以围绕请求创建一个 OperationContextScope 以更改某些请求属性。在 OperationContextScope 中,您有一个有效的 OperationContext.Current 实例,它允许通过 OutgoingMessageHeaders 集合操作消息头。使用此方法可以将标头的控制深入到应用程序代码中。您必须负责在需要的地方复制适当的代码。

两个链接(来自 WCF 团队的某个人)通过大量代码示例更详细地讨论了这一点:

于 2012-04-27T14:57:46.743 回答