扩展Wcf call security service, 手动添加 Soap Security Head.
有次我们有个项目需要Call 一个 Java 的 web service, Soap包中需要一个 Security Head
-
<soapenv:Header>
-
<wsse:Security soapenv:mustUnderstand="1" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
-
<wsse:UsernameToken xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" wsu:Id="UsernameToken-1" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
-
<wsse:Username>username</wsse:Username>
-
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">password</wsse:Password>
-
</wsse:UsernameToken>
-
</wsse:Security>
-
</soapenv:Header>
但是.net 默认的 Credentials 添加的 UserName 不符合这种格式
-
orgClient.ClientCredentials.UserName.UserName = "userName";
-
orgClient.ClientCredentials.UserName.Password = "password";
所以总是报错
System.Web.Services.Protocols.SoapHeaderException: An error was
discovered processing the <wsse: Security> header
没奈何,就只有用力气活,手动的把这段WSSE 的 head 添加到 Soap 包里面去了。
-
orgClient.Endpoint.EndpointBehaviors.Add(new CustomEndpointBehavior());
下面是Behavior
-
/// <summary>
-
/// Represents a run-time behavior extension for a client endpoint.
-
/// </summary>
-
public class CustomEndpointBehavior : IEndpointBehavior
-
{
-
/// <summary>
-
/// Implements a modification or extension of the client across an endpoint.
-
/// </summary>
-
/// <param name="endpoint">The endpoint that is to be customized.</param>
-
/// <param name="clientRuntime">The client runtime to be customized.</param>
-
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
-
{
-
clientRuntime.ClientMessageInspectors.Add(new ClientMessageInspector());
-
}
-
-
/// <summary>
-
/// Implement to pass data at runtime to bindings to support custom behavior.
-
/// </summary>
-
/// <param name="endpoint">The endpoint to modify.</param>
-
/// <param name="bindingParameters">The objects that binding elements require to support the behavior.</param>
-
public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
-
{
-
// Nothing special here
-
}
-
-
/// <summary>
-
/// Implements a modification or extension of the service across an endpoint.
-
/// </summary>
-
/// <param name="endpoint">The endpoint that exposes the contract.</param>
-
/// <param name="endpointDispatcher">The endpoint dispatcher to be modified or extended.</param>
-
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
-
{
-
// Nothing special here
-
}
-
-
/// <summary>
-
/// Implement to confirm that the endpoint meets some intended criteria.
-
/// </summary>
-
/// <param name="endpoint">The endpoint to validate.</param>
-
public void Validate(ServiceEndpoint endpoint)
-
{
-
// Nothing special here
-
}
-
}
请注意13行红色部分的代码,相当于一层层的使用了Provider 的模式
-
/// <summary>
-
/// Represents a message inspector object that can be added to the <c>MessageInspectors</c> collection to view or modify messages.
-
/// </summary>
-
public class ClientMessageInspector : IClientMessageInspector
-
{
-
/// <summary>
-
/// Enables inspection or modification of a message before a request message is sent to a service.
-
/// </summary>
-
/// <param name="request">The message to be sent to the service.</param>
-
/// <param name="channel">The WCF client object channel.</param>
-
/// <returns>
-
/// The object that is returned as the <paramref name="correlationState " /> argument of
-
/// the <see cref="M:System.ServiceModel.Dispatcher.IClientMessageInspector.AfterReceiveReply(System.ServiceModel.Channels.Message@,System.Object)" /> method.
-
/// This is null if no correlation state is used.The best practice is to make this a <see cref="T:System.Guid" /> to ensure that no two
-
/// <paramref name="correlationState" /> objects are the same.
-
/// </returns>
-
public object BeforeSendRequest(ref System.ServiceModel.Channels.Message request, IClientChannel channel)
-
{
-
SoapSecurityHeader header = new SoapSecurityHeader("UsernameToken-1", UserName, Password, "");
-
-
request.Headers.Add(header);
-
-
return header.Id;
-
}
-
-
/// <summary>
-
/// Enables inspection or modification of a message after a reply message is received but prior to passing it back to the client application.
-
/// </summary>
-
/// <param name="reply">The message to be transformed into types and handed back to the client application.</param>
-
/// <param name="correlationState">Correlation state data.</param>
-
public void AfterReceiveReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
-
{
-
var a = reply;
-
// Nothing special here
-
}
-
}
下面是写入Head的部分
-
public class SoapSecurityHeader : MessageHeader
-
{
-
private readonly string _password, _username, _nonce;
-
private readonly DateTime _createdDate;
-
-
public SoapSecurityHeader(string id, string username, string password, string nonce)
-
{
-
_password = password;
-
_username = username;
-
_nonce = nonce;
-
_createdDate = DateTime.Now;
-
this.Id = id;
-
}
-
-
public string Id { get; set; }
-
-
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"; }
-
}
-
-
protected override void OnWriteStartHeader(XmlDictionaryWriter writer, MessageVersion messageVersion)
-
{
-
writer.WriteStartElement("wsse", Name, Namespace);
-
writer.WriteXmlnsAttribute("wsse", Namespace);
-
}
-
-
protected override void OnWriteHeaderContents(XmlDictionaryWriter writer, MessageVersion messageVersion)
-
{
-
writer.WriteStartElement("wsse", "UsernameToken", Namespace);
-
writer.WriteAttributeString("Id", "UsernameToken-10");
-
writer.WriteAttributeString("wsu", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd");
-
-
writer.WriteStartElement("wsse", "Username", Namespace);
-
writer.WriteValue(_username);
-
writer.WriteEndElement();
-
-
writer.WriteStartElement("wsse", "Password", Namespace);
-
writer.WriteAttributeString("Type", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText");
-
writer.WriteValue(_password);
-
writer.WriteEndElement();
-
-
writer.WriteStartElement("wsse", "Nonce", Namespace);
-
writer.WriteAttributeString("EncodingType", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary");
-
writer.WriteValue(_nonce);
-
writer.WriteEndElement();
-
-
writer.WriteStartElement("wsse", "Created", Namespace);
-
writer.WriteValue(_createdDate.ToString("YYYY-MM-DDThh:mm:ss"));
-
writer.WriteEndElement();
-
-
writer.WriteEndElement();
-
}
-
}
至此大功告成!
专注云开发 目前选定的开发平台是 Azure 和 Salesforce
选定的开发工具是 Asp.net MVC 和 Force.com