Pourquoi mes clients .NET du service REST enverraient-ils chaque requête sans en-tête d’authentification, puis la réessayer avec un en-tête d’authentification?

Nous exécutons un service Web REST avec une API nécessitant que les clients utilisent l’authentification de base . Nous avons créé un ensemble d’échantillons soignés dans différentes langues et expliquant comment nous connecter à notre service. Maintenant, j’examine les journaux IIS du service et constate que le modèle suivant se produit assez souvent:

  • une demande arrive, est rejetée avec le code HTTP 401
  • la même demande est renvoyée et réussit

qui ressemble à la première demande est envoyé sans en-têtes d’ autorisation , puis la deuxième est envoyée avec les en-têtes corrects et réussit. La plupart du temps, l’enregistrement de journal contient “user-agent”, qui est la même chaîne que celle que nous avons insérée dans notre exemple .NET.

Je suppose donc que le problème concerne uniquement les programmes .NET. Le problème n’est pas reproduit avec notre exemple de code; je suppose donc que les utilisateurs ont modifié le code d’une manière ou d’une autre ou ont écrit le leur à partir de rien.

Nous avons essayé de contacter les utilisateurs, mais apparemment, ils ne veulent pas investir du temps dans la recherche. Il serait donc agréable de trouver le scénario le plus probable qui mène à ce comportement des programmes .NET.

Pourquoi feraient-ils cela? Pourquoi n’attacheraient-ils pas les en-têtes lors de la première tentative?

C’est le comportement par défaut des classes HttpClient et HttpWebRequest qui est exposé de la manière suivante.

Remarque: Le texte ci-dessous explique le comportement sous-optimal provoquant le problème décrit dans la question. Très probablement, vous ne devriez pas écrire votre code comme ça. Faites défiler ci-dessous jusqu’au code corrigé

Dans les deux cas, instancier un object NetworkCredenatial et y définir le nom d’utilisateur et le mot de passe.

 var credentials = new NetworkCredential( username, password ); 

Si vous utilisez la propriété HttpWebRequest – set .Credentials :

 webRequest.Credentials = credentials; 

Si vous utilisez HttpClient – transmettez l’object credentials à HttpClientHandler (code modifié à partir d’ ici ):

 var client = new HttpClient(new HttpClientHandler() { Credentials = credentials }) 

Puis lancez Fiddler et lancez la requête. Vous verrez ce qui suit:

  • la demande est envoyée sans en-tête d’ autorisation
  • le service répond avec HTTP 401 et WWW-Authenticate: Basic realm = “UrRealmHere”
  • la demande est renvoyée avec l’en-tête d’ autorisation appropriée (et réussit)

Ce comportement est expliqué ici – le client ne sait pas à l’avance que le service nécessite Basic et tente de négocier le protocole d’authentification (et si le service nécessite l’envoi Digest d’ en-têtes Basic en mode open est inutile et peut compromettre le client).

Remarque: Ici, l’explication du comportement sous-optimal se termine et une meilleure approche est expliquée. Très probablement, vous devriez utiliser le code ci-dessous au lieu du code ci-dessus.

Dans les cas où il est connu que le service nécessite Basic, cette demande supplémentaire peut être éliminée de la manière suivante:

Ne définissez pas .Credentials , ajoutez plutôt les en-têtes manuellement en utilisant le code à partir d’ ici . Encoder le nom d’utilisateur et mot de passe:

 var encoded = Convert.ToBase64Ssortingng( Encoding.ASCII.GetBytes( Ssortingng.Format( "{0}:{1}", username, password ) ) ); 

Lorsque vous utilisez HttpWebRequest ajoutez-le aux en-têtes:

 request.Headers.Add( "Authorization", "Basic " + encoded ); 

et lorsque vous utilisez HttpClient ajoutez-le aux en-têtes par défaut:

 client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue( "Basic", encoded ); 

Lorsque vous le faites, la demande est envoyée avec les en-têtes d’autorisation appropriés à chaque fois. Notez que vous ne devez pas définir .Credentials , sinon, si le nom d’utilisateur ou le mot de passe est incorrect, la même demande sera envoyée deux fois, avec de mauvaises informations d’identification et les deux fois renvoyant HTTP 401.