2009-09-01 7 views
14

J'ai reçu un service Web écrit en Java auquel je ne peux pas apporter de modifications. Il nécessite l'authentification de l'utilisateur avec l'authentification de base pour accéder à l'une des méthodes. La façon suggérée d'interagir avec ce service dans .NET consiste à utiliser Visual Studio 2005 avec WSE 3.0 installé.Impossible d'appeler le service Web avec l'authentification de base à l'aide de WCF

Ceci est un problème, car le projet utilise déjà Visual Studio 2008 (ciblant .NET 2.0). Je pourrais le faire dans VS2005, mais je ne veux pas lier le projet à VS2005 ou le faire en créant un assemblage dans VS2005 et en incluant cela dans la solution VS2008 (qui lie essentiellement le projet à 2005 pour tout changement futur à l'assemblage). Je pense que l'une ou l'autre de ces options rendrait les choses compliquées pour les nouveaux développeurs en les forçant à installer WSE 3.0 et empêcher le projet d'utiliser 2008 et les fonctionnalités de .NET 3.5 dans le futur ... je crois vraiment en utilisant WCF est le chemin à parcourir.

Je me suis intéressé à l'utilisation de WCF pour cela, mais je ne sais pas comment faire pour que le service WCF comprenne qu'il doit envoyer les en-têtes d'authentification avec chaque requête. Je reçois des erreurs 401 lorsque je tente de faire quelque chose avec le service Web.

C'est ce que mon code ressemble à:

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

Cela courir et jeter l'exception suivante:

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

Et cela a une exception intérieure:

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

Toute idée de ce qui pourrait causer ce problème serait grandement appréciée.

Répondre

26

Première question: est-ce un service Java basé sur SOAP ou REST que vous essayez d'appeler?

À l'heure actuelle, avec le "webHttpBinding", vous utilisez une approche REST. Si le service Java est un service SOAP, vous devez alors remplacer votre liaison par "basicHttpBinding".

IF il est un service SOAP, vous devriez essayer ceci:

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

Je l'ai utilisé cela avec divers services Web et fonctionne - la plupart du temps.

Si cela ne fonctionne pas, vous devrez en savoir plus sur ce que ce service Web Java attend et comment lui envoyer les informations pertinentes.

Marc

+0

Marc, Pouvez-vous me montrer comment le code et config si elle est REST service Java basé? – rajibdotnet

+2

La propriété ClientCredentials n'apparaît pas du tout pour moi après avoir tapé le proxy. – rajibdotnet

+1

@rajibdotnet: Eh bien, le code dans la question est fondamentalement ce que vous devez appeler un service basé sur REST .... si cela n'aide pas: s'il vous plaît ** poser votre propre question ** afin que les gens puissent répondre ... –

3

Je vais ajouter à cela aussi basé sur un problème similaire que je viens de vivre. J'ai auto-généré la config/proxy avec VS - mais la config créée ne fonctionnait pas réellement.

Bien que le mode de sécurité = "Transport" ait été défini correctement, le paramètre clientCredentialType = "Basic" n'a pas été défini. J'ai ajouté à cela ma config et cela n'a toujours pas fonctionné. Ensuite, je fait retiré la sécurité des messages que l'outil créé depuis le service que je suis en contact est SSL + Basic seulement:

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

Voila - cela a fonctionné.Je ne sais pas pourquoi cela a eu un effet étant donné que l'élément ne spécifiait pas la sécurité au niveau des messages ... mais c'était le cas.

6

Tout d'abord mettez ce qui suit dans votre app.config ou votre web.config. (Pas besoin de changer ce que vous vous déplacez à travers des environnements):

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

Modifier l'attribut de contrat au nom Namespace.Interface en conséquence. Notez le mode de sécurité = TransportCredentialOnly

Maintenant, pour changer par programmation le point final et de transmettre les informations d'identification, utilisez le code suivant:

  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

Je ne comprends pas comment le credentialBehavior est appliqué à la chaîne? Il semble que vous ne trouviez que les informations d'identification du client et que vous l'appliquiez à un nouveau credentialBehavior Var. Vous définissez ensuite le nom d'utilisateur et le mot de passe de cette variable ... Si je ne me trompe pas, cela n'a rien à voir avec les fixations ou – SoftwareSavant