C# WCF 服务,阅读soapenv 标头安全部分

Posted

技术标签:

【中文标题】C# WCF 服务,阅读soapenv 标头安全部分【英文标题】:C# WCF Service, read soapenv header security section 【发布时间】:2021-06-24 02:30:14 【问题描述】:

我正在寻找一种解决方法来读取传入的 soapenv => 安全部分。

我一直在尝试从传入的请求中获取soapenv,但没有成功:

int operationIndex = OperationContext.Current.IncomingMessageHeaders.FindHeader("Security", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
string operation = OperationContext.Current.IncomingMessageHeaders.GetHeader<string>(operationIndex);

这是一个关于如何格式化标题的示例:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:tem="http://tempuri.org/">
  <soapenv:Header>
      <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
        <wsse:UsernameToken wsu:Id="UsernameToken-1">
            <wsse:Username>TheUsername</wsse:Username>
            <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">XXXXXXXXXXXXXXXX</wsse:Password>
            <wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">XXXXXXXXXXXXX</wsse:Nonce>
            <wsu:Created>XXXXXXXXXX</wsu:Created>
        </wsse:UsernameToken>
        </wsse:Security>
   </soapenv:Header>
   <soapenv:Body>
      <tem:AMethod>
         <!--Optional:-->
         <tem:field>2</tem:field>
      </tem:AMethod>
   </soapenv:Body>
</soapenv:Envelope>

还有其他方法可以读取传入的肥皂标题吗?

编辑

刚刚找到了另一种获取soapheader的方法

var headerContent = OperationContext.Current.IncomingMessageHeaders.Select((value, i) => new  i, value ).ToList().Where(x => x.value.Name.ToLower().Equals("security")).FirstOrDefault();
XmlDictionaryReader xr = OperationContext.Current.IncomingMessageHeaders.GetReaderAtHeader(headerContent.i);
string xmlSecurityHeader = xr.ReadOuterXml();

【问题讨论】:

没有运气是什么意思?操作指数是-1还是别的? IncomingMessageHeaders 实现 IEnumerable。您是否尝试枚举所有标题以查看其中的内容? 我刚刚找到了另一种获取相关标头的方法:code var headerContent = OperationContext.Current.IncomingMessageHeaders.Select((value, i) => new i, value ).ToList( ).Where(x => x.value.Name.ToLower().Equals("security")).FirstOrDefault(); XmlDictionaryReader xr = OperationContext.Current.IncomingMessageHeaders.GetReaderAtHeader(headerContent.i);字符串 xmlSecurityHeader = xr.ReadOuterXml() code 【参考方案1】:

可以试试messageinspector,在客户端实现IClientMessageInspector接口,在服务端实现IDispatchMessageInspector接口。您可以拦截请求和回复。

这是客户端上的示例:

     public class ClientMessageLogger : IClientMessageInspector

    public void AfterReceiveReply(ref Message reply, object correlationState)
    
        string outputstr = $"Server reply message received by the client:\nreply\n";
        Console.WriteLine(outputstr);
    

    public object BeforeSendRequest(ref Message request, IClientChannel channel)
    
        string outputText = $"The request message that the client will send:\nrequest\n";
        Console.WriteLine(outputText);
        return null;

    

[AttributeUsage(AttributeTargets.Interface)]
public class CustomBehavior : Attribute, IContractBehavior

    public Type TargetContract => typeof(ServiceReference1.ICalculator);
    public void AddBindingParameters(ContractDescription contractDescription, ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
    
        return;
    

    public void ApplyClientBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, ClientRuntime clientRuntime)
    
        clientRuntime.ClientMessageInspectors.Add(new ClientMessageLogger());
    
    public void ApplyDispatchBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, DispatchRuntime dispatchRuntime)
    
        return;
    

    public void Validate(ContractDescription contractDescription, ServiceEndpoint endpoint)
    
        return;
    

这是服务器上的示例:

public class CustomMessageInspector : IDispatchMessageInspector
    
        public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
        
            string displayText = $"The request message received by the server:\nrequest\n";
            Console.WriteLine(displayText);
            return null;
        

        public void BeforeSendReply(ref Message reply, object correlationState)
        
            string displayText = $"Server reply message:\nreply\n";
            Console.WriteLine(displayText);
        
    
    [AttributeUsage(AttributeTargets.Interface)]
    public class CustomBehavior : Attribute, IContractBehavior
    
        public void AddBindingParameters(ContractDescription contractDescription, ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
        
            return;
        

        public void ApplyClientBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, ClientRuntime clientRuntime)
        
            return;
        
        public void ApplyDispatchBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, DispatchRuntime dispatchRuntime)
        
            dispatchRuntime.MessageInspectors.Add(new CustomMessageInspector());
        

        public void Validate(ContractDescription contractDescription, ServiceEndpoint endpoint)
        
            return;
        
    

最后在接口上方添加[CustomBehavior],在客户端,接口在你的服务引用中。

【讨论】:

以上是关于C# WCF 服务,阅读soapenv 标头安全部分的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Jquery Ajax 发送自定义标头并使用 C# 在 WCF 服务中检索相同的标头值?

C#消费soap WS在VerifyIncomingMessage中返回安全头错误

SOAP WCF 将 Signature 和 BinarySecurityToken 添加到标头

在 C# 中以编程方式创建 WCF 客户端的标头(wsse)部分

以编程方式添加终结点标头安全 WCF

在 wcf 中添加用于安全身份验证的自定义标头