C# 如何在WCF中向soap消息添加安全标头,
我正在尝试在WCF中添加SOAP安全头用户名令牌,很抱歉,我在上一篇文章中发布了我的所有跟踪信息,但得到了一些更多的方法,并在这里添加了可能会起作用的方法。现在我得到了一个例外 “深度为“0”时无法调用'WriteEndElement'。”C# 如何在WCF中向soap消息添加安全标头,,c#,wcf,soap,C#,Wcf,Soap,我正在尝试在WCF中添加SOAP安全头用户名令牌,很抱歉,我在上一篇文章中发布了我的所有跟踪信息,但得到了一些更多的方法,并在这里添加了可能会起作用的方法。现在我得到了一个例外 “深度为“0”时无法调用'WriteEndElement'。” 如果需要添加,请建议任何其他场景,等待专家的回复。在OnWriteHeaderContent中,您已经注释掉了一些WriteStarteElement调用,但没有注释掉它们对应的WriteEndElement调用-如果我计算正确,方法末尾有两个不必要的wri
如果需要添加,请建议任何其他场景,等待专家的回复。在OnWriteHeaderContent中,您已经注释掉了一些WriteStarteElement调用,但没有注释掉它们对应的WriteEndElement调用-如果我计算正确,方法末尾有两个不必要的writer.WriteEndElement调用。@nodots:感谢您的回复,但在调试时我仍然可以看到header部分正在成帧,但在运行时没有添加header。下面是发送SOAP请求时的xml请求。>0@nodots:对此有什么想法/建议吗?在OnWriteHeaderContents中,您已经注释掉了一些WriteStarteElement调用,但没有注释掉它们对应的WriteEndElement调用-如果我计算正确,在方法末尾有两个不必要的writer.WriteEndElement调用。@nodots:谢谢您的回复,但在调试期间,我仍然可以看到header部分正在帧化,但在运行时没有添加任何header。下面是发送SOAP请求时的xml请求。>0@nodots:对此有什么想法/建议吗?在OnWriteHeaderContents中,您已经注释掉了一些WriteStarteElement调用,但没有注释掉它们对应的WriteEndElement调用-如果我计算正确,在方法末尾有两个不必要的writer.WriteEndElement调用。@nodots:谢谢您的回复,但在调试期间,我仍然可以看到header部分正在帧化,但在运行时没有添加任何header。下面是发送SOAP请求时的xml请求。>0@nodots:对此有什么想法/建议吗?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Security.Cryptography;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
using System.ServiceModel.Web;
using System.Text;
using System.Xml;
using Microsoft.Web.Services3.Design;
using Microsoft.Web.Services3;
//using CustomAssertion.ServiceReference1;
namespace test
{
public class InspectorBehavior : IEndpointBehavior
{
public ClientInspector ClientInspector { get; set; }
public InspectorBehavior(ClientInspector clientInspector)
{
ClientInspector = clientInspector;
}
public void Validate(ServiceEndpoint endpoint)
{ }
public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
{
}
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
{ }
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
if (this.ClientInspector == null) throw new InvalidOperationException("Caller must supply ClientInspector.");
clientRuntime.MessageInspectors.Add(ClientInspector);
}
}
public class ClientInspector : IClientMessageInspector
{
public MessageHeader[] Headers { get; set; }
public ClientInspector(params MessageHeader[] headers)
{
Headers = headers;
}
public object BeforeSendRequest(ref Message request, IClientChannel channel)
{
if (Headers != null)
{
for (int i = Headers.Length - 1; i >= 0; i--)
request.Headers.Insert(0, Headers[i]);
}
return request;
}
public void AfterReceiveReply(ref Message reply, object correlationState)
{
}
}
public class SecurityHeader : MessageHeader
{
public string SystemUser { get; set; }
public string SystemPassword { get; set; }
public SecurityHeader(string systemUser, string systemPassword)
{
SystemUser = systemUser;
SystemPassword = systemPassword;
}
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)
{
var nonce = new byte[64];
RandomNumberGenerator.Create().GetBytes(nonce);
string created = DateTime.Now.ToString("yyyy-MM-ddThh:mm:ss.msZ");
writer.WriteStartElement("wsse", "UsernameToken", Namespace);
writer.WriteXmlnsAttribute("wsse", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd");
writer.WriteValue(SystemUser);
//writer.WriteStartElement("wsse", "Username", null);
//writer.WriteString(SystemUser);
writer.WriteEndElement();//End Username
writer.WriteStartElement("wsse", "Password", Namespace);
//writer.WriteStartElement("wsse", "Password", null);
writer.WriteAttributeString("Type", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest");
writer.WriteValue(ComputePasswordDigest(SystemPassword, nonce, created));
//writer.WriteString(ComputePasswordDigest(SystemPassword, nonce, created));
writer.WriteEndElement();//End Password
writer.WriteStartElement("wsse", "Nonce", null);
writer.WriteAttributeString("EncodingType", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary");
writer.WriteBase64(nonce, 0, nonce.Length);
writer.WriteEndElement();//End Nonce
// writer.WriteStartElement("wsse", "Created", null);
// writer.WriteString(created);
// writer.WriteEndElement();//End Created
// writer.WriteEndElement();//End UsernameToken
writer.Flush();
}
private string ComputePasswordDigest(string secret, byte[] nonceInBytes, string created)
{
byte[] createdInBytes = Encoding.UTF8.GetBytes(created);
byte[] secretInBytes = Encoding.UTF8.GetBytes(secret);
byte[] concatenation = new byte[nonceInBytes.Length + createdInBytes.Length + secretInBytes.Length];
Array.Copy(nonceInBytes, concatenation, nonceInBytes.Length);
Array.Copy(createdInBytes, 0, concatenation, nonceInBytes.Length, createdInBytes.Length);
Array.Copy(secretInBytes, 0, concatenation, (nonceInBytes.Length + createdInBytes.Length), secretInBytes.Length);
return Convert.ToBase64String(SHA1.Create().ComputeHash(concatenation));
}
}
public class Service1 : IService1
{
public string security(int a)
{
ServiceReference1.Service1Client action = new ServiceReference1.Service1Client();
action.Endpoint.Behaviors.Add(new InspectorBehavior(
new ClientInspector(new SecurityHeader("username", "password"))));
return action.GetData(8);
}
}
}