以编程方式更改WCF服务端点后维护安全性配置

时间:2016-03-21 13:55:36

标签: c# asp.net web-services wcf authentication

我是一个ASP.NET MVC应用程序,我们使用多个外部服务。

我们以这种方式为web.config中的每个服务定义端点:

<endpoint address="http://tempuri.org/myExternalServiceEndPointAddress"
    binding="basicHttpBinding" bindingConfiguration="myExternalServiceBinding" contract="myExternalServiceContract" name="MyExternalServiceName">
    <headers>
      <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
        <wsse:UsernameToken>
          <wsse:Username>myUsername</wsse:Username>
          <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">myPassword</wsse:Password>
        </wsse:UsernameToken>
      </wsse:Security>
    </headers>
  </endpoint>

现在,当切换到生产环境时,我们必须通过特定服务发现实际的端点URL,因为它们可以在没有警告的情况下进行更改。找到新端点后,我们在执行任何方法调用之前更改端点URL:

myserviceClientObject.Endpoint.Address = new EndpointAddress(newEndpointUrl);

完成此操作后,方法调用在newEndpointUrl中正确处理,但调用已丢失包含验证的标头节点。

我们尝试通过

以编程方式添加身份验证
myServiceClientObject.ClientCredentials.Username.Username = myUsername;
myServiceClientObject.ClientCredentials.Username.Password = myPassword;

但是,该服务似乎无法识别此身份验证(而前一个身份验证工作正常,直到我们更改了端点)。

非常感谢任何见解或建议。

1 个答案:

答案 0 :(得分:0)

我终于解决了这个问题。

我们最终做的是将带有所需标题的对象连接到WCF管道。

为此,我们创建了一个在服务中添加客户端行为的类,以及另一个定义了注入的行为本身的类。

以下是代码:

添加行为的类

public class EndpointAddCredentials : IEndpointBehavior {

    public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters) { }

    public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime) {
        clientRuntime.MessageInspectors.Add(new SimpleMessageInspector());
    }

    public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) { }

    public void Validate(ServiceEndpoint endpoint) { }

}

在发送请求之前定义和应用它的类

public class SimpleMessageInspector : IClientMessageInspector, IDispatchMessageInspector {

    public void AfterReceiveReply(ref Message reply, object correlationState) {
    }

    public object BeforeSendRequest(ref Message request, IClientChannel channel) {


        UsernameToken authentication = new UsernameToken(remoteServiceUsername, remoteServicePassword, PasswordOption.SendPlainText); //Plain text is server requirement, we cannot do anything

        var webUserHeader = MessageHeader.CreateHeader("Security", 
            "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", authentication.GetXml(new XmlDocument()));
        request.Headers.Add(webUserHeader);

        return null;
    }

    public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext) {
        return null;
    }

    public void BeforeSendReply(ref Message reply, object correlationState) {
    }
}

然后,在服务重定向之后,我们只需要将行为添加到客户端对象

serviceObject.Endpoint.Behaviors.Add(new EndpointAddCredentials()); 

有了这个,对服务器的请求包括我们正在寻找的安全定义,服务器接受了它们。