2009-09-01 5 views
14

Mi è stato fornito un servizio Web scritto in Java a cui non sono possibile apportare modifiche. Richiede all'utente di autenticarsi con l'autenticazione di base per accedere a uno qualsiasi dei metodi. Il modo suggerito per interagire con questo servizio in .NET è utilizzando Visual Studio 2005 con WSE 3.0 installato.Impossibile chiamare il servizio Web con l'autenticazione di base utilizzando WCF

Questo è un problema, poiché il progetto sta già utilizzando Visual Studio 2008 (con targeting .NET 2.0). Potrei farlo in VS2005, tuttavia non voglio legare il progetto a VS2005 o farlo creando un assemblaggio in VS2005 e includendolo nella soluzione VS2008 (che fondamentalmente lega il progetto al 2005 in ogni caso per eventuali future modifiche all'assemblaggio). Penso che una di queste opzioni renderebbe le cose complicate ai nuovi sviluppatori costringendoli a installare WSE 3.0 e impedire al progetto di poter utilizzare 2008 e funzionalità in .NET 3.5 in futuro ... cioè, credo davvero che si possa usare WCF è la strada da percorrere.

Ho cercato di utilizzare WCF per questo, tuttavia non sono sicuro su come ottenere che il servizio WCF comprenda che è necessario inviare le intestazioni di autenticazione insieme a ciascuna richiesta. Ottengo 401 errori quando tento di fare qualsiasi cosa con il servizio web.

Questo è ciò che il mio codice è simile:

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); 

Questo verrà eseguito e gettare la seguente eccezione:

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

e questo ha un eccezione interna di:

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

Qualsiasi idea su cosa potrebbe causare questo problema sarebbe molto apprezzata.

risposta

26

Prima domanda: si tratta di un servizio Java basato su SOAP o REST che si sta tentando di chiamare?

In questo momento, con "webHttpBinding", si sta utilizzando un approccio basato su REST. Se il servizio Java è un servizio SOAP, sarà necessario modificare l'associazione in modo che sia "basicHttpBinding".

SE è un servizio basato su SOAP, si dovrebbe provare questo:

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"; 

Ho usato questo con i vari servizi web e funziona - la maggior parte del tempo.

Se ciò non funziona, dovrete scoprire di più su cosa si aspetta il servizio web Java e su come inviarlo a tali informazioni pertinenti.

Marc

+0

Marc, mi puoi mostrare come codificare e configurazione se è REST servizio Java basato? – rajibdotnet

+2

La proprietà ClientCredentials non viene visualizzata per me dopo aver digitato il proxy. – rajibdotnet

+1

@rajibdotnet: beh, il codice nella domanda è fondamentalmente quello che è necessario chiamare un servizio basato su REST .... se questo non aiuta: per favore ** fai la tua domanda ** così la gente può rispondere ... –

3

Vorrei aggiungere a questo come pure sulla base di un problema simile ho appena vissuto. Ho auto-generato il config/proxy con VS - ma la configurazione che ha creato non ha funzionato.

Anche se la modalità di sicurezza = "Trasporto" era impostata correttamente, non aveva clientCredentialType = set "Base". Ho aggiunto a questo la mia configurazione e ancora non ha funzionato. Poi in realtà ho rimosso la protezione dei messaggi che lo strumento creato da quando il servizio che sto contattando è SSL + di base solo:

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

Voila - ha funzionato.

Non sono sicuro del motivo per cui questo ha avuto un effetto considerando che l'elemento non ha specificato la sicurezza a livello di messaggio ... ma lo ha fatto.

6

Prima di tutto inserisci quanto segue in app.config o in web.config. (Nessuna necessità di cambiare questo come si sposta attraverso gli ambienti):

<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> 

Cambiare l'attributo contratto per il nome Namespace.Interface conseguenza. nota la modalità di protezione = TransportCredentialOnly

Ora per modificare a livello di endpoint e passare le credenziali, utilizzare il seguente codice:

  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

Non capisco come viene applicato il canale di credentialBehavior? Sembra che tu trovi <> le credenziali del client e applicalo a un nuovo Var credentialBehavior. Quindi imposti il ​​nome utente e la password di quella variabile ... Se non sbaglio, questo non ha nulla a che fare con le associazioni o – SoftwareSavant