一、前提
1.Java Webservice使用的cxf webservice框架生成,使用了usernameToken方式的ws-security用户安全认证
2..net客户端采用WCF方式调用
二、说明
使用soapUI进行调试,得到Post包格式如下:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ser="http://service.weather.api.ceair.com/">
<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>
<wsse:Username>ceair_api</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">ceair_api</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
</soapenv:Header>
<soapenv:Body>
<ser:getCityWeatherAll>
<!--Optional:-->
<arg0>上海</arg0>
<!--Optional:-->
<arg1>?</arg1>
<arg2>?</arg2>
</ser:getCityWeatherAll>
</soapenv:Body>
</soapenv:Envelope>
三、代码
using System;
using System.ServiceModel.Description;
using System.ServiceModel;
using System.ServiceModel.Dispatcher;
using System.ServiceModel.Channels;
using System.Xml;
using System.ServiceModel.Configuration;
public class CustomBehavior : Attribute, IEndpointBehavior
{
#region IEndpointBehavior Members
public void AddBindingParameters(ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
{
}
public void ApplyClientBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime clientRuntime)
{
var clientCredentials = endpoint.Behaviors.Find<ClientCredentials>();
if (clientCredentials != null)
{
var inspector = new CustomClientMessageInspector(clientCredentials.UserName.UserName, clientCredentials.UserName.Password);
clientRuntime.MessageInspectors.Add(inspector);
}
}
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.EndpointDispatcher endpointDispatcher)
{
}
public void Validate(ServiceEndpoint endpoint)
{
}
#endregion
}
public class CustomBehaviorExtensionElement : BehaviorExtensionElement
{
protected override object CreateBehavior()
{
return new CustomBehavior();
}
public override Type BehaviorType
{
get
{
return typeof(CustomBehavior);
}
}
}
class CustomMessageHeader : MessageHeader
{
private const string PREFIX_SEC = "wsse";
private const string PREFIX_SOAP = "soapenv";
private const string NAMESPACE_SEC = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd";
private const string NAMESPACE_SOAP = "http://schemas.xmlsoap.org/soap/envelope/";
public string UserName { get; private set; }
public string Password { get; private set; }
public CustomMessageHeader(string userName, string password)
{
UserName = userName;
Password = password;
}
protected override void OnWriteHeaderContents(XmlDictionaryWriter writer, MessageVersion messageVersion)
{
base.OnWriteStartHeader(writer, messageVersion);
}
protected override void OnWriteStartHeader(System.Xml.XmlDictionaryWriter writer, MessageVersion messageVersion)
{
writer.WriteStartElement(PREFIX_SOAP, "Header", NAMESPACE_SOAP);
//Security
writer.WriteStartElement(PREFIX_SEC, "Security", NAMESPACE_SEC);
writer.WriteAttributeString(PREFIX_SOAP, "mustUnderstand", NAMESPACE_SOAP, "1");
writer.WriteXmlnsAttribute(PREFIX_SEC, NAMESPACE_SEC);
writer.WriteXmlnsAttribute(PREFIX_SOAP, NAMESPACE_SOAP);
//UsernameToken
writer.WriteStartElement(PREFIX_SEC, "UsernameToken", NAMESPACE_SEC);
//Username
writer.WriteElementString(PREFIX_SEC, "Username", NAMESPACE_SEC, UserName);
//Password
writer.WriteStartElement(PREFIX_SEC, "Password", NAMESPACE_SEC);
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.WriteEndElement();
writer.WriteEndElement();
writer.WriteEndElement();
}
public override string Name
{
get { return "Security"; }
}
public override string Namespace
{
get { return NAMESPACE_SEC; }
}
}
public class CustomClientMessageInspector : IDispatchMessageInspector, IClientMessageInspector
{
public string UserName { get; private set; }
public string Password { get; private set; }
public CustomClientMessageInspector()
{
}
public CustomClientMessageInspector(string userName, string password)
{
UserName = userName;
Password = password;
}
#region Message Inspector of the Service
public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
{
return null;
}
public void BeforeSendReply(ref Message reply, object correlationState)
{
}
#endregion
#region Message Inspector of the Consumer
public void AfterReceiveReply(ref Message reply, object correlationState)
{
}
public object BeforeSendRequest(ref Message request, IClientChannel channel)
{
MessageHeader header = new CustomMessageHeader(UserName, Password);
request.Headers.Add(header);
return null;
}
#endregion
}
客户端WCF调用代码
ServiceReference1.WeatherServiceV2Client client = new ServiceReference1.WeatherServiceV2Client();
client.ClientCredentials.UserName.UserName = "ceair_api";
client.ClientCredentials.UserName.Password = "ceair_api";
var weather = client.getCityWeatherAll("上海", "", false);
app.config wcf配置
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="WeatherServiceV2ImplServiceSoapBinding" />
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://172.20.32.145:8080/ceair-api/weather" behaviorConfiguration="clientInspectorsAdded"
binding="basicHttpBinding" bindingConfiguration="WeatherServiceV2ImplServiceSoapBinding"
contract="ServiceReference1.WeatherServiceV2" name="WeatherServiceV2ImplPort" />
</client>
<behaviors>
<endpointBehaviors>
<behavior name="clientInspectorsAdded">
<clientInterceptors />
</behavior>
</endpointBehaviors>
</behaviors>
<extensions>
<behaviorExtensions>
<add name="clientInterceptors" type="JavaWebServiceCaller.CustomBehaviorExtensionElement, JavaWebServiceCaller, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
</behaviorExtensions>
</extensions>
</system.serviceModel>