ejemplo - servicio rest c# json
¿Por qué mis clientes.NET del servicio REST enviarán todas las solicitudes sin encabezados de autenticación y luego volverán a intentarlo con un encabezado de autenticación? (1)
Pasamos a ejecutar un servicio web REST con API que requiere que los clientes usen la autenticación básica . Diseñamos un conjunto de muestras ordenadas en varios idiomas que muestran cómo interactuar con nuestro servicio. Ahora estoy revisando los registros de IIS del servicio y veo que el siguiente patrón ocurre con bastante frecuencia:
- llega una solicitud, se rechaza con el código HTTP 401
- la misma solicitud se reenvió y tiene éxito
que parece que la primera solicitud se envía sin encabezados de Autorización y luego la segunda se envía con los encabezados correctos y tiene éxito. La mayoría de las veces, el registro de registro contiene "user-agent", que es la misma cadena que hemos plantado en nuestra muestra de .NET.
Así que supongo que el problema es solo con los programas .NET. El problema no se reproduce con nuestro código de muestra, así que supongo que los usuarios de alguna manera modificaron el código o escribieron el suyo desde cero.
Intentamos contactar a los usuarios pero aparentemente no quieren invertir tiempo en investigación. Así que sería bueno encontrar cuál es el escenario más probable que conduce a este comportamiento de los programas .NET.
¿Por qué harían esto? ¿Por qué no unirían los encabezados en el primer intento?
Este es el comportamiento predeterminado de las clases HttpClient
y HttpWebRequest
que se expone de la siguiente manera.
Nota: El texto a continuación explica el comportamiento subóptimo que causa el problema descrito en la pregunta. Lo más probable es que no deberías escribir tu código así. En su lugar, desplácese hacia abajo hasta el código corregido
En ambos casos, crea una instancia de un objeto NetworkCredenatial
y configura el nombre de usuario y la contraseña allí
var credentials = new NetworkCredential( username, password );
Si usa HttpWebRequest
- establece la propiedad .Credentials
:
webRequest.Credentials = credentials;
Si usa HttpClient
, pase el objeto de credenciales a HttpClientHandler
(código alterado desde aquí ):
var client = new HttpClient(new HttpClientHandler() { Credentials = credentials })
Luego ejecute Fiddler e inicie la solicitud. Verás lo siguiente:
- la solicitud se envía sin encabezado de autorización
- el servicio responde con HTTP 401 y WWW-Authenticate: Basic realm = "UrRealmHere"
- la solicitud se reenvía con el encabezado de Autorización adecuado (y tiene éxito)
Este comportamiento se explica aquí : el cliente no sabe de antemano que el servicio requiere Basic e intenta negociar el protocolo de autenticación (y si el servicio requiere que Digest envíe encabezados básicos en abierto es inútil y puede comprometer al cliente).
Nota: Aquí termina la explicación del comportamiento subóptimo y se explica un mejor enfoque. Lo más probable es que deba usar el código de abajo en lugar del código anterior.
En los casos en que se sabe que el servicio requiere Básico, la solicitud adicional se puede eliminar de la siguiente manera:
No establezca .Credentials
, en su lugar agregue los encabezados manualmente usando el código de aquí . Codifique el nombre de usuario y la contraseña:
var encoded = Convert.ToBase64String( Encoding.ASCII.GetBytes(
String.Format( "{0}:{1}", username, password ) ) );
Al usar HttpWebRequest
agréguelo a los encabezados:
request.Headers.Add( "Authorization", "Basic " + encoded );
y al usar HttpClient
agréguela a los encabezados predeterminados:
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue( "Basic", encoded );
Cuando lo hace, la solicitud se envía con los encabezados de autorización correctos en todo momento. Tenga en cuenta que no debe establecer .Credentials
; de lo contrario, si el nombre de usuario o la contraseña son incorrectos, la misma solicitud se enviará dos veces, ambas con las credenciales incorrectas y las dos veces, por supuesto, produciendo HTTP 401.