How can I add authorization header to the request

2020-02-06 03:05发布

I'm working on a Windows Form application and there's a WCF service that needs to be called. I need to add a header (authorization - custom) to the request before it's sent to the service. I have a custom inspector class as well. I tried the following but the service is not called, somehow, and it returns an exception.

public object BeforeSendRequest(ref Message request, IClientChannel channel)
{
    MessageHeader header = MessageHeader.CreateHeader("Authorization", "", "Basic Y19udGk6Q29udGlfQjNTVA==");
    OperationContext.Current.OutgoingMessageHeaders.Add(header);
    HttpRequestMessageProperty httpRequestProperty = new HttpRequestMessageProperty();
    httpRequestProperty.Headers.Add("Authorization", "Basic Y19udGk6Q29udGlfQjNTVA==");
    httpRequestProperty.Headers.Add(HttpRequestHeader.UserAgent, "Continental");
            OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = httpRequestProperty;
    sentMessages.Add(request.ToString());
    return null;
}

I also tried simplest way like this one:

MessageHeader header = MessageHeader.CreateHeader("Authorization", "", "Basic Y19udGk6Q29udGlfQjNTVA==");
request.Headers.Add(header);

but it's the same, authorization header is added but it does not reach the service, how can I know what header is received by the service? I used SOAP UI and service responds well when I add such a header manually in the request (before running).

4条回答
趁早两清
2楼-- · 2020-02-06 03:14

I know this is late but I ran across this post so decided to fill this in, in case I ever need to remember this again. This worked for me:

  1. Create the Message Inspector:

    Public Class AuthenticationHeader
      Implements IClientMessageInspector
    
    Private itsUser As String
    Private itsPass As String
    
    Public Sub New(ByVal user As String, ByVal pass As String)
        itsUser = user
        itsPass = pass
    End Sub
    
    Public Sub AfterReceiveReply(ByRef reply As Message, correlationState As Object) Implements IClientMessageInspector.AfterReceiveReply
        Console.WriteLine("Received the following reply: '{0}'", reply.ToString())
    End Sub
    
    Public Function BeforeSendRequest(ByRef request As Message, channel As IClientChannel) As Object Implements IClientMessageInspector.BeforeSendRequest
        Dim hrmp As HttpRequestMessageProperty = request.Properties("httpRequest")
        Dim encoded As String = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(itsUser + ":" + itsPass))
        hrmp.Headers.Add("Authorization", "Basic " + encoded)
        Return request
      End Function
    End Class
    
  2. Write the Behavior:

    Public Class AuthenticationHeaderBehavior
    Implements IEndpointBehavior
    
    Private ReadOnly itsUser As String
    Private ReadOnly itsPass As String
    
    Public Sub New(ByVal user As String, ByVal pass As String)
        MyBase.New()
        itsUser = user
        itsPass = pass
    End Sub
    
    Public Sub AddBindingParameters(endpoint As ServiceEndpoint, bindingParameters As BindingParameterCollection) Implements IEndpointBehavior.AddBindingParameters
    End Sub
    
    Public Sub ApplyClientBehavior(endpoint As ServiceEndpoint, clientRuntime As ClientRuntime) Implements IEndpointBehavior.ApplyClientBehavior
        clientRuntime.MessageInspectors.Add(New AuthenticationHeader(itsUser, itsPass))
    End Sub
    
    Public Sub ApplyDispatchBehavior(endpoint As ServiceEndpoint, endpointDispatcher As EndpointDispatcher) Implements IEndpointBehavior.ApplyDispatchBehavior
    End Sub
    
    Public Sub Validate(endpoint As ServiceEndpoint) Implements IEndpointBehavior.Validate
    End Sub
    End Class
    
  3. Add it to your endpoint:

      Dim binding As New WebHttpBinding(WebHttpSecurityMode.Transport)
      binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None
    
      ChlFactory = New WebChannelFactory(Of IMyServiceContract)(binding, New Uri(url))
      ChlFactory.Endpoint.Behaviors.Add(New WebHttpBehavior())
      ChlFactory.Endpoint.Behaviors.Add(New AuthenticationHeaderBehavior(user, pass))
      Channel = ChlFactory.CreateChannel()
    
查看更多
太酷不给撩
3楼-- · 2020-02-06 03:16

If there's some problem with your BeforeSend method, this is how I implemented it when adding authentication to some webservice calls.

private const string Authorization = "Authorization";
public object BeforeSendRequest(ref Message request, IClientChannel channel)
    {
        object httpRequestMessageObject;
        if (request.Properties.TryGetValue(
            HttpRequestMessageProperty.Name, out httpRequestMessageObject))
        {
            var httpRequestMessage = httpRequestMessageObject as HttpRequestMessageProperty;

            if (string.IsNullOrWhiteSpace(httpRequestMessage.Headers[Authorization]))
            {
                httpRequestMessage.Headers[Authorization] = "Basic Y19udGk6Q29udGlfQjNTVA==";
            }
        }
        else
        {
            var httpRequestMessage = new HttpRequestMessageProperty();
            httpRequestMessage.Headers.Add(Authorization, "Basic Y19udGk6Q29udGlfQjNTVA==");

            request.Properties.Add(HttpRequestMessageProperty.Name, httpRequestMessage);
        }

        return null;
    }
查看更多
时光不老,我们不散
4楼-- · 2020-02-06 03:23

The simplest way is to add it on the client side:

using (MyServ.ServiceClient proxy = new MyServ.ServiceClient())
{
     using (new System.ServiceModel.OperationContextScope(proxy.InnerChannel))
     {
         MessageHeader head = MessageHeader.CreateHeader("Authorization", "http://yournamespace.com/v1", data);
         OperationContext.Current.OutgoingMessageHeaders.Add(head);
     }
}

and retrieve it on the server side:

string  auth = OperationContext.Current.IncomingMessageHeaders.
GetHeader<string>("Authorization", "http://mynamespace.com/v1");

I also suggest that you check these articles:

Authorization Header is missing in Http request using WCF

WCF Service with wsHttpBinding - Manipulating HTTP request headers

查看更多
▲ chillily
5楼-- · 2020-02-06 03:30

The problem with your solution is that it would add an HTTP header. What you need is a SOAP header, however. That could be done like this...

using(new OperationContextScope(client.InnerChannel)) 
{
    // Add a SOAP Header to an outgoing request
    MessageHeader aMessageHeader = MessageHeader.CreateHeader("UserInfo", "http://tempuri.org", userInfo);
    OperationContext.Current.OutgoingMessageHeaders.Add(aMessageHeader);
}
查看更多
登录 后发表回答