¿Cómo puedo suprimir el diálogo de autenticación del navegador?

85

Mi aplicación web tiene una página de inicio de sesión que envía credenciales de autenticación a través de una llamada AJAX. Si el usuario ingresa el nombre de usuario y la contraseña correctos, todo está bien, pero si no, sucede lo siguiente:

  1. El servidor web determina que, aunque la solicitud incluía un encabezado de autorización bien formado, las credenciales en el encabezado no se autentican correctamente.
  2. El servidor web devuelve un código de estado 401 e incluye uno o más encabezados WWW-Authenticate que enumeran los tipos de autenticación admitidos.
  3. El navegador detecta que la respuesta a mi llamada en el objeto XMLHttpRequest es un 401 y la respuesta incluye encabezados WWW-Authenticate. A continuación, aparece un cuadro de diálogo de autenticación que solicita, nuevamente, el nombre de usuario y la contraseña.

Todo esto está bien hasta el paso 3. No quiero que aparezca el diálogo, quiero manejar la respuesta 401 en mi función de devolución de llamada AJAX. (Por ejemplo, mostrando un mensaje de error en la página de inicio de sesión). Quiero que el usuario vuelva a ingresar su nombre de usuario y contraseña, por supuesto, pero quiero que vean mi formulario de inicio de sesión amigable y tranquilizador, no el feo y predeterminado del navegador. diálogo de autenticación.

Por cierto, no tengo control sobre el servidor, por lo que no es una opción hacer que devuelva un código de estado personalizado (es decir, algo que no sea 401).

¿Hay alguna forma de que pueda suprimir el diálogo de autenticación? En particular, ¿puedo suprimir el cuadro de diálogo Se requiere autenticación en Firefox 2 o posterior? ¿Hay alguna forma de suprimir el cuadro de diálogo Conectar a [host] en IE 6 y versiones posteriores?


Editar
Información adicional del autor (18 de septiembre):
Debo agregar que el problema real con la aparición del cuadro de diálogo de autenticación del navegador es que no brinda información suficiente al usuario.

El usuario acaba de ingresar un nombre de usuario y contraseña a través del formulario en la página de inicio de sesión, cree que los ha escrito correctamente y ha hecho clic en el botón enviar o presionar enter. Su expectativa es que lo llevarán a la página siguiente o tal vez le digan que ha ingresado su información de manera incorrecta y debe intentarlo nuevamente. Sin embargo, en su lugar se le presenta un cuadro de diálogo inesperado.

El cuadro de diálogo hace ningún reconocimiento del hecho de que sólo hizo ingresar un nombre de usuario y contraseña. No indica claramente que hubo un problema y que debería intentarlo de nuevo. En cambio, el cuadro de diálogo presenta al usuario información críptica como "El sitio dice: ' [reino] '". Donde [reino] es un nombre de reino corto que solo un programador podría amar.

Los diseñadores de Web broswer toman nota: nadie preguntaría cómo suprimir el diálogo de autenticación si el diálogo en sí fuera simplemente más fácil de usar. La única razón por la que estoy haciendo un formulario de inicio de sesión es que nuestro equipo de administración de productos considera con razón que los diálogos de autenticación de los navegadores son horribles.

dgvid
fuente
1
La respuesta es que no existe una buena respuesta. Los trucos sugeridos por Marijn son lo más cercano posible. Por supuesto, usar una autenticación personalizada comprendida por el servidor y su JavaScript, pero no por el navegador, también funcionará, si eso es posible.
dgvid
He estado en el mismo problema y encontré este enlace en un comentario aquí en stackoverflow (no en mi blog): loudvchar.blogspot.ca/2010/11/… Espero que te ayude.
gies0r

Respuestas:

17

No creo que esto sea posible: si usa la implementación del cliente HTTP del navegador, siempre aparecerá ese cuadro de diálogo. Me vienen a la mente dos trucos:

  1. Tal vez Flash maneja esto de manera diferente (aún no lo he intentado), por lo que tener una película flash para hacer la solicitud podría ayudar.

  2. Puede configurar un 'proxy' para el servicio al que está accediendo en su propio servidor y hacer que modifique un poco los encabezados de autenticación para que el navegador no los reconozca.

Marijn
fuente
"No es posible" parece ser la respuesta correcta, aunque sospecho que el truco "proxie" funcionaría.
dgvid
@Stobor ¡La respuesta aceptada para el duplicado que publicó en realidad enlaza a esta pregunta como su respuesta!
8bitjunkie
3
@ 7SpecialGems Buena captura. No estaba sugiriendo que fuera un engaño, lo vinculé a la respuesta específica (la WWW-Authenticate) que se publicó 4 años después de la respuesta aceptada. Aunque en retrospectiva, no puedo recordar por qué estaba mirando eso, o cómo lo probé.
Stobor
1
Intento detectar el error 401 no autorizado con este código: $ .ajaxSetup ({statusCode: {401: function () {RedirectToLogin ();}}}); Pero IE siempre muestra el diálogo de autenticación del navegador. ¿Cómo puedo suprimir este diálogo en ASP.Net MVC 2?
PaulP
@PaulP, como se ha dicho, necesita un proxy que elimine las respuestas del código de estado 401 de su encabezado WWW-Authenticate, o algún tipo de implementación de servidor personalizada.
Motes
51

Encontré el mismo problema aquí, y el ingeniero de backend de mi empresa implementó un comportamiento que aparentemente se considera una buena práctica: cuando una llamada a una URL devuelve un 401, si el cliente ha configurado el encabezado X-Requested-With: XMLHttpRequest, el servidor deja caer el www-authenticateencabezado en su respuesta.

El efecto secundario es que no aparece la ventana emergente de autenticación predeterminada.

Asegúrese de que su llamada a la API tenga el X-Requested-Withencabezado configurado en XMLHttpRequest. Si es así, no hay nada que hacer excepto cambiar el comportamiento del servidor de acuerdo con esta buena práctica ...

Antoine Banctel-Chevrel
fuente
3
Si el backend está basado en Java / Spring, el DelegatingAuthenticationEntryPointmaneja este comportamiento por usted.
Derek Slife
Gracias por esto. Muchas bibliotecas han adoptado este comportamiento, incluido Devise
josephnvu
1
¿Alguna idea de cómo hacer esto en nginx? "cuando una llamada a una URL devuelve un 401, si el cliente ha configurado el encabezado X-Requested-With: XMLHttpRequest, el servidor descarta el encabezado www-authenticate en su respuesta".
markmnl
18

El navegador muestra un mensaje de inicio de sesión cuando se cumplen las dos condiciones siguientes:

  1. El estado HTTP es 4xx
  2. WWW-Authenticate el encabezado está presente en la respuesta

Si puede controlar la respuesta HTTP, puede eliminar el WWW-Authenticateencabezado de la respuesta y el navegador no mostrará el diálogo de inicio de sesión.

Si no puede controlar la respuesta, puede configurar un proxy para filtrar el WWW-Authenticateencabezado de la respuesta.

Hasta donde yo sé (no dude en corregirme si me equivoco), no hay forma de evitar el mensaje de inicio de sesión una vez que el navegador recibe el WWW-Authenticateencabezado.

rustyx
fuente
Buena información. Con respecto a los WWW-Authenticatevalores de encabezado válidos , consulte stackoverflow.com/a/1748451/225217
Brice Roncace
6

Me doy cuenta de que esta pregunta y sus respuestas son muy antiguas. Pero, terminé aquí. Quizás otros también lo hagan.

Si tiene acceso al código para el servicio web que devuelve el 401. Simplemente cambie el servicio para devolver un 403 (Prohibido) en esta situación en lugar del 401. El navegador no solicitará credenciales en respuesta a un 403. 403 es el código correcto para un usuario autenticado que no está autorizado para un recurso específico. Cuál parece ser la situación del OP.

Del documento IETF en 403:

Un servidor que recibe credenciales válidas que no son adecuadas para obtener acceso debe responder con el código de estado 403 (Prohibido)

Jim Reineri
fuente
4

En Mozilla puedes lograrlo con el siguiente script cuando creas el objeto XMLHttpRequest:

xmlHttp=new XMLHttpRequest();
xmlHttp.mozBackgroundRequest = true;
xmlHttp.open("GET",URL,true,USERNAME,PASSWORD);
xmlHttp.send(null);

La segunda línea evita el cuadro de diálogo ....

HNygard
fuente
1
Esto parece no hacer nada bajo Firefox 2. Da como resultado un error de seguridad DOM, NS_ERROR_DOM_SECURITY_ERR código 1000, bajo Firefox 3.
dgvid
2

¿Qué tecnología de servidor utiliza y hay algún producto en particular que utilice para la autenticación?

Dado que el navegador solo está haciendo su trabajo, creo que debe cambiar las cosas en el lado del servidor para no devolver un código de estado 401. Esto se puede hacer utilizando formularios de autenticación personalizados que simplemente devuelvan el formulario nuevamente cuando falla la autenticación.

jan.vdbergh
fuente
2

En la tierra de Mozilla, establecer el parámetro mozBackgroundRequest de XMLHttpRequest ( docs ) en true suprime esos diálogos y hace que las solicitudes simplemente fallen. Sin embargo, no sé qué tan buena es la compatibilidad con varios navegadores (incluido si la calidad de la información de error en esas solicitudes fallidas es muy buena en todos los navegadores).

rakslice
fuente
El prefijo moz- implica que no es compatible con varios navegadores (a menos que pueda encontrar parámetros similares que funcionen en cada uno de los otros navegadores).
Brilliand
2

jan.vdbergh tiene la verdad, si puede cambiar el 401 en el lado del servidor por otro código de estado, el navegador no captará ni pintará la ventana emergente. Otra solución podría ser cambiar el encabezado WWW-Authenticate por otro encabezado personalizado. No creo por qué los diferentes navegadores no pueden soportarlo, en algunas versiones de Firefox podemos hacer la solicitud xhr con mozBackgroundRequest, pero ¿en los otros navegadores? aquí, hay un vínculo interesante con este problema en Chromium.

Kalamarico
fuente
1

Tengo el mismo problema con MVC 5 y VPN donde siempre que estamos fuera de la DMZ usando la VPN, tenemos que responder a este mensaje del navegador. Usando .net simplemente manejo el enrutamiento del error usando

<customErrors defaultRedirect="~/Error"  >
  <error statusCode="401" redirect="~/Index"/>
</customErrors>

hasta ahora ha funcionado porque la acción de índice bajo el controlador doméstico valida al usuario. La vista en esta acción, si el inicio de sesión no es exitoso, tiene controles de inicio de sesión que utilizo para iniciar la sesión del usuario usando la consulta LDAP pasada a los Servicios de directorio:

      DirectoryEntry entry = new DirectoryEntry("LDAP://OurDomain");
      DirectorySearcher Dsearch = new DirectorySearcher(entry);
      Dsearch.Filter = "(SAMAccountName=" + UserID + ")";
      Dsearch.PropertiesToLoad.Add("cn");

Si bien esto ha funcionado bien hasta ahora, debo informarle que todavía lo estoy probando y que el código anterior no ha tenido ninguna razón para ejecutarse, por lo que está sujeto a eliminación ... las pruebas actualmente incluyen intentar descubrir un caso en el que el segundo conjunto de código es de más utilidad. Nuevamente, este es un trabajo en progreso, pero como podría ser de ayuda o estimular tu cerebro para algunas ideas, decidí agregarlo ahora ... Lo actualizaré con los resultados finales una vez que se hayan realizado todas las pruebas.

Clarence
fuente
1

Estoy usando Node, Express & Passport y estaba luchando con el mismo problema. Lo hice funcionar estableciendo explícitamente el www-authenticateencabezado en una cadena vacía. En mi caso, se veía así:

(err, req, res, next) => {
  if (err) {
    res._headers['www-authenticate'] = ''
    return res.json(err)
  }
}

¡Espero que ayude a alguien!

John Knotts
fuente
0

Para aquellos que no usan C #, esto es lo ActionAttributeque regresa en 400lugar de 401y 'traga' el cuadro de diálogo de autenticación básica.

public class NoBasicAuthDialogAuthorizeAttribute : AuthorizeAttribute
{
    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
    {
        base.HandleUnauthorizedRequest(filterContext);
        filterContext.Result = new HttpStatusCodeResult(400);
    }
}

utilizar como sigue:

[NoBasicAuthDialogAuthorize(Roles = "A-Team")]
public ActionResult CarType()
{
 // your code goes here
}

Espero que esto te ahorre algo de tiempo.

Matas Vaitkevicius
fuente