2009-09-01 20 views
14

Me han proporcionado un servicio web escrito en Java que no puedo hacer ningún cambio. Requiere que el usuario se autentique con autenticación básica para acceder a cualquiera de los métodos. La forma sugerida de interactuar con este servicio en .NET es mediante el uso de Visual Studio 2005 con WSE 3.0 instalado.No se puede llamar al servicio web con autenticación básica usando WCF

Esto es un problema, ya que el proyecto ya está utilizando Visual Studio 2008 (orientación .NET 2.0). Podría hacerlo en VS2005, sin embargo, no quiero vincular el proyecto a VS2005 o hacerlo creando un ensamblaje en VS2005 e incluyendo eso en la solución VS2008 (que básicamente relaciona el proyecto con 2005 de todos modos para cualquier cambio futuro en el ensamblaje)) Creo que cualquiera de estas opciones complicaría las cosas para los nuevos desarrolladores al obligarlos a instalar WSE 3.0 y evitar que el proyecto pueda usar 2008 y las características en .NET 3.5 en el futuro ... es decir, realmente creo que usar WCF es el camino a seguir.

He estado buscando el uso de WCF para esto, sin embargo no estoy seguro de cómo lograr que el servicio WCF entienda que necesita enviar los encabezados de autenticación junto con cada solicitud. Recibo 401 errores cuando intento hacer algo con el servicio web.

Esto es lo que se ve mi código como:

WebHttpBinding webBinding = new WebHttpBinding(); 
ChannelFactory<MyService> factory = 
    new ChannelFactory<MyService>(webBinding, new EndpointAddress("http://127.0.0.1:80/Service/Service/")); 
factory.Endpoint.Behaviors.Add(new WebHttpBehavior()); 
factory.Credentials.UserName.UserName = "username"; 
factory.Credentials.UserName.Password = "password"; 

MyService proxy = factory.CreateChannel(); 
proxy.postSubmission(_postSubmission); 

Esto ejecutará y lanzar la siguiente excepción:

The HTTP request is unauthorized with client authentication scheme 'Anonymous'. The authentication header received from the server was 'Basic realm=realm'.

Y esto tiene una excepción interna de:

The remote server returned an error: (401) Unauthorized.

Cualquier idea sobre lo que podría estar causando este problema sería muy apreciada.

Respuesta

26

Primera pregunta: ¿se trata de un servicio Java basado en SOAP o REST que está intentando llamar?

En este momento, con "webHttpBinding", está utilizando un enfoque basado en REST. Si el servicio Java es un servicio SOAP, entonces necesitarás cambiar tu enlace para que sea "basicHttpBinding" en su lugar.

SI es un servicio basado en SOAP, usted debe tratar de esto:

BasicHttpBinding binding = new BasicHttpBinding(); 

binding.SendTimeout = TimeSpan.FromSeconds(25); 

binding.Security.Mode = BasicHttpSecurityMode.Transport; 
binding.Security.Transport.ClientCredentialType = 
           HttpClientCredentialType.Basic; 

EndpointAddress address = new EndpointAddress(your-url-here); 

ChannelFactory<MyService> factory = 
      new ChannelFactory<MyService>(binding, address); 

MyService proxy = factory.CreateChannel(); 

proxy.ClientCredentials.UserName.UserName = "username"; 
proxy.ClientCredentials.UserName.Password = "password"; 

He utilizado este con varios servicios web y funciona - la mayor parte del tiempo.

Si eso no funciona, tendrá que averiguar más sobre lo que espera el servicio web Java y cómo enviarle esa información relevante.

Marc

+0

Marc, ¿Me puede mostrar cómo codificar y config si es RESTO basado en el servicio de Java? – rajibdotnet

+2

La propiedad ClientCredentials no aparece en absoluto después de que escribí el proxy. – rajibdotnet

+1

@rajibdotnet: bueno, el código en la pregunta es básicamente lo que necesita para llamar a un servicio REST .... si eso no ayuda: por favor ** haga su propia pregunta ** para que la gente pueda responder ... –

3

voy a añadir a esto también basado en un problema similar que se ha producido. Genere automáticamente la configuración/proxy con VS, pero la configuración que creó no funcionó.

Aunque tenía el modo de seguridad = "Transporte" establecido correctamente, no tenía clientCredentialType = "Basic" establecido. Agregué a eso mi configuración y todavía no funcionó. Entonces realmente me quita la seguridad de los mensajes que la herramienta creada ya que el servicio que estoy en contacto con son SSL + solamente básica:

<message clientCredentialType="UserName" algorithmSuite="Default" /> 

Voila - funcionó.

No estoy seguro de por qué esto tuvo un efecto considerando que el elemento no especificó la seguridad del nivel de mensaje ... pero lo hizo.

6

Antes que nada, ponga lo siguiente en su app.config o su web.config. (Sin necesidad de cambiar esta medida que se mueven a través de entornos):

<system.serviceModel> 
     <bindings> 
      <basicHttpBinding> 
       <binding name="BasicHttpBinding_IConfigService"> 
        <security mode="TransportCredentialOnly"> 
         <transport clientCredentialType="Basic"/> 
        </security> 
       </binding> 
      </basicHttpBinding> 
     </bindings> 
     <client> 
      <endpoint address="http://localhost:55283/ConfigService.svc" 
       binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IConfigService" 
       contract="IConfigService" name="BasicHttpBinding_IService" /> 
     </client> 
    </system.serviceModel> 

En el atributo contrato al nombre Namespace.Interface en consecuencia. Nota el modo de seguridad = TransportCredentialOnly

Ahora cambiar mediante programación el punto final y pasar las credenciales, utilice el siguiente código:

  var myBinding = new BasicHttpBinding("BasicHttpBinding_IConfigService"); 
      var myEndpoint = new EndpointAddress("http://yourbaseurl/configservice.svc"); 
      var myChannelFactory = new ChannelFactory<IConfigService>(myBinding, myEndpoint); 

      var credentialBehaviour = myChannelFactory.Endpoint.Behaviors.Find<ClientCredentials>(); 
      credentialBehaviour.UserName.UserName = @"username"; 
      credentialBehaviour.UserName.Password = @"password"; 

      IConfigService client = null; 

      try 
      { 
       client = myChannelFactory.CreateChannel(); 
       var brands = client.YourServiceFunctionName(); 
       ((ICommunicationObject)client).Close(); 
      } 
      catch (Exception ex) 
      { 
       if (client != null) 
       { 
        ((ICommunicationObject)client).Abort(); 
       } 
      } 
+0

¿No entiendo cómo se está aplicando el comportamiento de credencial al canal? Parece que acaba de encontrar <> las credenciales del cliente y aplicarlo a un nuevo comportamiento de credenciales Var. A continuación, establece el nombre de usuario y la contraseña de esa variable ... Si no me equivoco, eso no tiene nada que ver con las vinculaciones o – SoftwareSavant

Cuestiones relacionadas