Я создал веб-службу REST, используя DataSnap в Delphi XE. Я вызываю методы сервера, используя объект JavaScript XMLHttpRequest. Я передаю имя пользователя и пароль для аутентификации в четвертом и пятом необязательных параметрах метода Open XMLHttpRequest.
Когда я загружаю свой сервер DataSnap в Delphi и подключаю отладчик к IIS (я использую IIS 7.5), я вижу, что первый раз, когда я вызываю один из серверных методов, приводит к тому, что событие OnUserAuthenticate DSAuthenticationManager вызывается дважды.
При первом вызове параметры пользователя и пароля обработчика события OnUserAuthenticate представляют собой пустые строки. При втором вызове в этих параметрах появляются имя пользователя и пароль, которые я передал в методе XMLHttpRequest Open.
После аутентификации пользователя любые последующие вызовы любого из методов сервера с использованием XMLHttpRequest приводят к одному вызову обработчика событий OnUserAuthenticate, при этом имя пользователя и пароль отображаются в параметрах пользователя и пароля соответственно.
Я проверил исходный код ряда классов 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 следует вызывать только один раз за сеанс. После изучения предоставленной им ссылки стало очевидно, что мне не удалось захватить и вернуть идентификатор сеанса. Вот пример кода, который работает, на этот раз асинхронно. Он захватывает идентификатор сеанса и сохраняет его в скрытом поле. Затем он передает этот идентификатор сеанса обратно при каждом последующем вызове в заголовке 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.