Я создал REST Web-сервис, используя DataSnap в Delphi XE. Я вызываю методы сервера, используя объект JavaScript XMLHttpRequest. Я передаю имя пользователя и пароль для аутентификации в четвертом и пятом необязательных параметрах метода Open XMLHttpRequest.
Когда я загружаю свой сервер DataSnap в Delphi и подключаю отладчик к IIS (я использую IIS 7.5), я вижу, что при первом вызове одного из серверных методов дважды вызывается событие OnUserAuthenticate DSAuthenticationManager.
В первом вызове параметры пользователя и пароля обработчика события OnUserAuthenticate являются пустыми строками. При втором вызове в этих параметрах появляются имя пользователя и пароль, которые я передал в методе XMLHttpRequest Open.
Как только пользователь прошел аутентификацию, любые последующие вызовы любого из серверных методов, использующих XMLHttpRequest, приводят к одному вызову обработчика события OnUserAuthenticate, при этом имя пользователя и пароль пользователя появляются в параметрах user и password соответственно.
Я проверил исходный код для ряда классов DataSnap и не нашел код, который вызвал бы этот эффект, что наводит меня на мысль, что это может происходить в браузере или IIS.
Почему OnUserAuthenticate вызывается дважды при первом вызове метода сервера, и что вызывает этот эффект?
В ответ на ответ Мэта Делонга я показываю одну из универсальных функций, которые я использую для вызова методов моего сервера. Этот конкретный метод делает синхронный вызов. Параметр baseURL обычно представляет собой строку, аналогичную http://mydomain.com/myservice/myservice.dll/datasnap/rest/tservermethods1,, а метод может быть myservermethod. Дополнительные параметры используются для передачи параметров методу сервера:
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);
}
Редактировать: Лекс Ли, похоже, прав, что IIS использует обычную аутентификацию только в случае неудачи при первом запросе. Кроме того, Мат прав, что OnUserAuthenticate следует вызывать только один раз за сеанс. После изучения предоставленной им ссылки стало очевидно, что мне не удалось перехватить и вернуть идентификатор сеанса. Вот пример кода, который работает, на этот раз асинхронно. Он захватывает sessionid и сохраняет его в скрытом поле. Затем он передает этот идентификатор сеанса обратно при каждом последующем вызове в заголовке 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);
}
Редактировать: Когда я впервые опубликовал эти два примера кода, я включил образцы имен пользователей и паролей в четвертый и пятый параметры открытого метода XMLHttpRequest. Я передавал эти значения явно во время тестирования. Передавать такие параметры не рекомендуется, поэтому я удалил эти параметры в этом редактировании. Если вы опустите эти пароли и не передадите их с помощью других методов (например, в заголовке вашего первого вызова метода REST-сервера), браузер отобразит диалоговое окно, запрашивающее у пользователя эту информацию. После ввода имени пользователя и пароля браузер запомнит эту информацию до конца сеанса. Если вы закроете, а затем снова откроете браузер и вызовете другой метод сервера REST, вам снова будет предложено ввести имя пользователя и пароль. Это предполагает, конечно, что вы отклоняете недопустимых пользователей через обработчик события OnUserAuthenticate.