2010-11-30 27 views
7

Estoy intentando agregar una función de seguridad personalizada donde el cliente agrega un token a cada llamada de servicio realizada por un cliente de Silverlight y luego el servicio puede acceder a este token para controlar un sistema de seguridad de la aplicación. Estoy intentando hacer esto implementando la interfaz IClientMessageInspector y vinculándola a mi cliente de servicio generado. No estoy usando el proxy generado por Visual Studio, sino mi propio cliente creado por ChannelFactory. He logrado encontrar varias soluciones en la web que parecen usar uno de dos métodos básicos. En primer lugar, agregue un encabezado a la colección de encabezados del mensaje presentado a IClientMessageInspector.BeforeSendRequest y, en segundo lugar, usando un HttpRequestMessageProperty para agregar la información como una propiedad al mensaje presentado a IClientMessageInspector.BeforeSendRequest. He estado probando ambos métodos sin ningún éxito. Parece que ambas técnicas agregan datos a la solicitud con éxito, pero no he podido acceder al servidor. Agregaría que esta es un área muy nueva para mí y es muy posible que haya perdido la respuesta en Internet debido a la inexperiencia.No puedo leer encabezados en el servicio WCF

El código para generar mi cliente es:

private ISecurityAdministrationContract CreateChannel() 
    { 
     if (factory == null) 
     { 
      lock (this) 
      { 
       // Create a custom binding that uses HTTP and binary encoding. 
       var elements = new List<BindingElement>(); 
       elements.Add(new BinaryMessageEncodingBindingElement()); 
       elements.Add(new HttpTransportBindingElement()); 
       var binding = new CustomBinding(elements); 

       // Create a channel factory for the service endpoint configured with the custom binding. 
       factory = new ChannelFactory<ISecurityAdministrationContract>(binding, new EndpointAddress(SecurityAdminServiceAddress)); 

       //Add my IClientMessageInspector 
       factory.Endpoint.Behaviors.Add(new ClientSecurityInterceptor()); 
      }     
     } 
     ISecurityAdministrationContract client = factory.CreateChannel(); 
     return client; 
    } 
     } 
     ISecurityAdministrationContract client = factory.CreateChannel(); 
     return client; 
    } 

el código para agregar mi encabezado a la solicitud es:

public object BeforeSendRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel) 
    { 
     //Method 1 
     MessageHeader header = MessageHeader.CreateHeader("MyFirstAuthentication", "ns", "AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEEE"); 
     request.Headers.Add(header); 

     //Method 2 
     HttpRequestMessageProperty httpRequestMessage; 
     httpRequestMessage = new HttpRequestMessageProperty(); 
     httpRequestMessage.Headers["MySecondAuthentication"] = "11111111-2222-3333-4444-5555555555555"; 
     request.Properties.Add(HttpRequestMessageProperty.Name, httpRequestMessage); 

     return null; 
    } 

El código anterior implementa ambas técnicas.

La llamada de servicio es atrapado por el violinista: (Nota: http reemplazó con ht_tp cos el sitio no me permite publicar hyoerlinks) ht_tp

POST: //127.0.0.1: 6785/SecurityAdministrationRelayService.svc/HTTP/1.1 Accept: / Referer: ht_tp: //ipv4.fiddler: 6785/ClientBin/Civica.Housing.xap Accept-Language: en-gb Content-Length: 400 Content-Type: aplicación/soap + msbin1 MySecondAuthentication: 11111111-2222-3333-4444-5555555555555 Accep t-Codificación: gzip, deflate User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; GTB5; InfoPath.2; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; .NET4.0C; .NET4.0E; .NET CLR 2.0.50727) Anfitrión: 127.0.0.1:6785 conexión: Keep-Alive Pragma: no-cache

V_ s _a_V_D Ahttp: //tempuri.org/ISecurityAdministrationContract/CreateAdvocateD ߔ_9 HJ9-D, D * @MyFirstAuthentication _ns% AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEEED _ @ http://ipv4.fiddler:6785/SecurityAdministrationRelayService.svc/ V @_CreateAdvocate_ http://tempuri.org/@ advocateVO {"Id": 0, "UserId": 4, "AdvocateForId": 8, "ValidFrom": "/ Fecha (1291127869690 + 0000) /", "ValidTo ": nulo} __

Esto parece contener la información del token para ambas técnicas.

El problema viene en el servidor cuando intento extraer esta información. Implementé IOperationInvoker e intenté encontrar el encabezado en IncomingMessageHeaders sin éxito.También busqué en IncomingMessageProperties pero no puedo ver ninguno de los detalles del encabezado agregado. Este es el código que estoy utilizando en el IOperationInvoker:

public object Invoke(object instance, object[] inputs, out object[] outputs) 
    { 
     PreInvoke(instance, inputs); 
     object returnedValue = null; 
     object[] outputparams = new object[] { }; 
     Exception exception = null; 
     try 
     { 
      returnedValue = originalInvoker.Invoke(instance, inputs, out outputparams); 
      outputs = outputparams; 
      return returnedValue; 
     } 
     catch (Exception e) 
     { 
      exception = e; throw; 
     } 
     finally 
     { 
      PostInvoke(instance, returnedValue, outputparams, exception); 
     } 
    } 


    protected virtual void PreInvoke(object instance, object[] inputs) 
    { 
     //Look for header directly 
     int index = System.ServiceModel.OperationContext.Current.IncomingMessageHeaders.FindHeader("MyFirstAuthentication", "ns"); 

     //Search via enumerator 
     foreach (var header in System.ServiceModel.OperationContext.Current.IncomingMessageHeaders) 
     { 
     } 

    } 

El FindHeader devuelve -1, mientras que el empadronador encuentra 5 cabeceras, a saber; 'Acción', 'MessageID', 'ReplyTo', 'VsDebuggerCausalityData' & 'To'.

La colección OperationContext.Current.IncomingMessageProperties contiene 4 entradas, a saber: 'Via', 'Seguridad', 'encoder' & 'System.ServiceModel.Channels.RemoteEndpointMessageProperty'

De hecho si me comente la línea de en mi cliente que agrega el IClientMessageInspector al ClienChannel, luego el http que el violinista informa cambios al omitir el detalle agregado, pero las colecciones de encabezado y propiedad en el mensaje entrante no se modifican.

Cualquier idea sobre cómo puedo acceder a esta información, o por qué no se presenta como parte de IncomingMessage sería muy gratamente recibida.

Respuesta

6

He respondido mi propia pregunta. No hay nada de malo con ninguno de los códigos anteriores, solo tiene que estar vinculado al lugar correcto. En mi solución completa llamo a un servicio del cliente de Silverlight que luego llama a un segundo servicio. De manera vergonzosa, había vinculado mi IOperationInvoker con el segundo servicio (doh). Cuando lo vinculé al servicio intermedio, el encabezado estaba disponible como se esperaba.

El código para leer el valor es:

  int index = OperationContext.Current.IncomingMessageHeaders.FindHeader("MyFirstAuthentication", "ns"); 
      if (index >= 0) 
      { 
       string value = OperationContext.Current.IncomingMessageHeaders.GetHeader<string>(index); 
      } 
2

Usted puede usar lo siguiente para acceder a un valor de encabezado:

var headers = OperationContext.Current.IncomingMessageProperties["httpRequest"]; 
var apiToken = ((HttpRequestMessageProperty)headers).Headers["<YourHeaderKey>"]; 
Cuestiones relacionadas