javascript - node - ¿Por qué se llama a OnUserAuthenticate dos veces en un servidor REST de DataSnap?
json server online (2)
No puedo decir con certeza por qué está viendo este comportamiento sin ver su código de servidor y el JavaScript exacto que está utilizando con el XHR. OnUserAuthenticate está destinado a ser llamado una vez, para una sesión.
Puede ver el protocolo XE DataSnap REST aquí: http://docwiki.embarcadero.com/RADStudio/en/DataSnap_REST_Messaging_Protocol#Session_Information
Se pretende que la primera llamada devuelva una ID de sesión, y se supone que todas las llamadas futuras especificarán eso. Si se hace esto, todas las llamadas, excepto la primera, usan la ID de sesión dada para omitir el proceso de autenticación y solo van al evento OnUserAuthorize, si se le asigna una.
Si ve OnUserAuthenticate llamado dos veces, es probable que se trate de un error a menos que sea algo extraño en el XHR o en la configuración de IIS.
Si pudiera proporcionar un poco más de detalle, me gustaría verlo de cerca.
Creé un servicio web REST usando DataSnap en Delphi XE. Estoy llamando a los métodos del servidor utilizando el objeto JavaScript XMLHttpRequest. Paso el nombre de usuario y la contraseña para la autenticación en los parámetros opcionales cuarto y quinto del método XMLHttpRequest Open.
Cuando cargo mi servidor DataSnap en Delphi y adjunto el depurador a IIS (estoy usando IIS 7.5) puedo ver que la primera vez que llamo a uno de los métodos del servidor da como resultado que el evento OnUserAuthenticate de DSAuthenticationManager se llame dos veces.
En la primera llamada, los parámetros de usuario y contraseña del controlador de eventos OnUserAuthenticate son cadenas vacías. En la segunda llamada, el nombre de usuario y la contraseña que pasé en el método XMLHttpRequest Open aparecen en esos parámetros.
Una vez que el usuario ha sido autenticado, cualquier llamada subsiguiente a cualquiera de los métodos del servidor usando XMLHttpRequest da como resultado una única llamada al controlador de eventos OnUserAuthenticate, con el nombre de usuario y la contraseña apareciendo en los parámetros de usuario y contraseña, respectivamente.
He inspeccionado el código fuente de varias clases de DataSnap y no he encontrado el código que causaría este efecto, lo que me lleva a pensar que este comportamiento puede originarse en el navegador o IIS.
¿Por qué se llama a OnUserAuthenticate dos veces después de la primera llamada al método del servidor y qué produce este efecto?
En respuesta a la respuesta de Mat DeLong, estoy mostrando una de las funciones genéricas que estoy usando para llamar a mis métodos de servidor. Este método particular hace una llamada síncrona. El parámetro baseURL normalmente es una cadena similar a http://mydomain.com/myservice/myservice.dll/datasnap/rest/tservermethods1 , y el método podría ser myservermethod. Los parámetros adicionales se utilizan para pasar parámetros al método del servidor:
function getJSONSync(baseURL, method) {
var request = new XMLHttpRequest();
var url = baseURL + method;
for (var i= 2; i < arguments.length; i++) {
url += "/" + arguments[i];
}
request.open("GET", encodeURI(url), false);
request.send(null);
if (request.status != 200) {
throw new Error(request.statusText);
}
return jQuery.parseJSON(request.responseText);
}
Editar: Lex Li parece ser correcto, que IIS solo está utilizando autenticación básica si falla en la primera solicitud. Además, Mat tiene razón en que OnUserAuthenticate solo debe invocarse una vez por sesión. Después de examinar el enlace que me brindó, era evidente que no capturaba y devolvía la identificación de la sesión. Aquí hay un ejemplo de código que funciona, esta vez de manera asilárgica. Captura el sessionid y lo almacena en un campo oculto. A continuación, devuelve esa id. De sesión en cada llamada posterior en un encabezado de Pragma.
function getJSONAsync(callback, baseURL, method) {
var request = new XMLHttpRequest();
var timedout = false;
request.onreadystatechange = function() {
if (request.readyState !== 4) { return }
if (timedout) { return }
if (request.status >= 200 && request.status < 300)
{
callback(jQuery.parseJSON(request.responseText));
//store the sessionid in a hidden field
$("#sessionid").val(request.getResponseHeader(''Pragma'').split('','')[0].split("=")[1]);
}
}
var url = baseURL + method;
for (var i= 3; i < arguments.length; i++) {
url += "/" + arguments[i];
}
request.open("GET", encodeURI(url), true);
//pass the sessionid in the Pragma header, if available
if (! $("#sessionid").val() == "") {
request.setRequestHeader("Pragma", "dssession="+$("#sessionid").val());
}
//time out if request does not complete in 10 seconds
var timer = setTimeout(function() { timedout = true; request.abort(); }, 10000);
request.send(null);
}
Editar: Cuando publiqué por primera vez estos dos ejemplos de código, incluí ejemplos de nombres de usuario y contraseñas en los parámetros cuarto y quinto del método abierto XMLHttpRequest. Estaba pasando estos valores explícitamente durante la prueba. No se recomienda pasar los parámetros de esta manera, así que eliminé esos parámetros en esta edición. Si omite estas contraseñas y no las pasa utilizando otros métodos (como en el encabezado de su primera invocación al método de servidor REST), el navegador mostrará un cuadro de diálogo en el que se le pedirá al usuario esta información. Una vez que se haya proporcionado el nombre de usuario y la contraseña, el navegador recordará esta información durante el resto de la sesión. Si cierra y luego vuelve a abrir el navegador e invoca otro método de servidor REST, una vez más se le cuestionará el nombre de usuario y la contraseña. Esto supone, por supuesto, que está rechazando usuarios no válidos a través del controlador de eventos OnUserAuthenticate.
Bueno, ese es un comportamiento típico de IIS para otras tecnologías, como ASP.NET.
La solicitud inicial no contiene sus credenciales de usuario y desencadena una respuesta 401. Luego, la segunda solicitud envía sus credenciales de usuario, luego IIS puede devolver 200.
No estoy seguro de si esto se aplica a DataSnap, pero si captura paquetes de red, puede descubrirlo.
http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.preauthenticate.aspx