2011-08-05 4 views
3

Delphi XE에서 DataSnap을 사용하여 REST 웹 서비스를 만들었습니다. XMLHttpRequest JavaScript 객체를 사용하여 서버 메소드를 호출하려고합니다. XMLHttpRequest Open 메소드의 네 번째 및 다섯 번째 선택적 매개 변수에 인증 용 사용자 이름과 암호를 전달합니다.OnUserAuthenticate가 DataSnap REST 서버에서 두 번 호출되는 이유는 무엇입니까?

DataSnap 서버를 Delphi에로드하고 IIS 7.5에 디버거를 연결하면 서버 메서드 중 하나를 호출하면 DSAuthenticationManager의 OnUserAuthenticate 이벤트가 두 번 호출되는 결과가 나타납니다.

첫 번째 호출에서 OnUserAuthenticate 이벤트 핸들러의 user 및 password 매개 변수는 빈 문자열입니다. 두 번째 호출에서는 XMLHttpRequest Open 메서드에서 전달한 사용자 이름과 암호가 해당 매개 변수에 나타납니다.

일단 사용자가 인증되면 XMLHttpRequest를 사용하는 서버 메서드에 대한 이후의 모든 호출은 사용자의 사용자 이름과 암호가 각각 User 매개 변수와 Password 매개 변수에 나타나는 OnUserAuthenticate 이벤트 처리기를 한 번 호출합니다.

많은 DataSnap 클래스의 소스 코드를 검사했는데이 효과가 발생할 수있는 코드를 찾지 못했습니다. 이로 인해 브라우저 나 IIS에서이 동작이 발생할 수 있다고 생각하게되었습니다.

첫 번째 서버 메서드 호출시 OnUserAuthenticate가 두 번 호출되는 이유는 무엇입니까?


Mat DeLong의 대답에 대한 응답으로, 저는 서버 메소드를 호출하기 위해 사용하는 일반 함수 중 하나를 보여주고 있습니다. 이 특별한 방법은 동기 호출을 만든다. 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는 기본 인증을 사용하는 것이 올바른 것으로 나타난다. 또한 Mat는 OnUserAuthenticate가 세션 당 한 번만 호출되어야한다는 것이 맞습니다. 그가 제공 한 링크를 검토 한 결과 세션 ID를 캡처하고 반환하지 못했습니다. 이번에는 비동기 적으로 작동하는 코드 예제가 있습니다. 그것은 세션 ID를 캡처하여 숨겨진 필드에 저장합니다. 그런 다음 Pragma 헤더의 각 후속 호출에서 해당 세션 ID를 다시 전달합니다.

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의 open 메소드의 네 번째와 다섯 번째 매개 변수 샘플 사용자 이름과 암호를 포함. 테스트 중에 명시 적으로이 값을 전달했습니다. 이와 같은 매개 변수를 전달하는 것은 좋지 않으므로이 편집에서 매개 변수를 제거했습니다. 이 암호를 생략하고 다른 메소드 (예 : 첫 번째 REST 서버 메소드 호출의 머리글과 같은)를 사용하여 암호를 전달하지 않으면 브라우저에 사용자에게이 정보를 묻는 대화 상자가 표시됩니다. 사용자 이름과 암호가 제공되면 브라우저는 나머지 세션 동안이 정보를 기억합니다. 브라우저를 닫았다가 다시 열고 다른 REST 서버 메소드를 호출하면 사용자 이름과 비밀번호를 다시 요구 받게됩니다. 물론 이것은 OnUserAuthenticate 이벤트 처리기를 통해 유효하지 않은 사용자를 거부하고 있다고 가정합니다.

답변

3

ASP.NET과 같은 다른 기술에 대한 일반적인 IIS 동작입니다.

초기 요청에 사용자 자격 증명이 포함되어 있지 않고 401 응답을 트리거합니다. 그런 다음 두 번째 요청이 사용자 자격 증명을 보내면 IIS는 200을 반환 할 수 있습니다.

이 사항이 DataSnap에 적용되는지는 확실하지 않지만 네트워크 패킷을 캡처하는 경우 알 수 있습니다.

http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.preauthenticate.aspx

+1

이것이 올바른 것으로 보입니다. wireshark를 사용하여 패킷을 검사했습니다. 첫 번째 요청에는 기본 인증 헤더 정보가 포함되지 않지만 두 번째 요청에는 기본 인증 헤더 정보가 포함되지 않습니다. 감사! –

2

서버 코드 및 XHR과 함께 사용하고있는 정확한 JavaScript를 보지 않고서 왜이 동작을하는지 확실히 말할 수는 없습니다.OnUserAuthenticate는 세션에 대해 한 번만 호출되도록 설계되었습니다. 첫 번째 호출은 세션 ID를 반환하고, 미래의 모든 통화가 그를 지정 해야하는 것을 목적으로한다 http://docwiki.embarcadero.com/RADStudio/en/DataSnap_REST_Messaging_Protocol#Session_Information

:

는 여기에서 XE의 DataSnap REST 프로토콜을 볼 수 있습니다. 이 작업이 끝나면 첫 번째 호출을 제외한 모든 호출은 지정된 세션 ID를 사용하여 인증 프로세스를 건너 뛰고 OnUserAuthorize 이벤트 (할당 된 경우)로만 이동합니다.

OnUserAuthenticate가 두 번 호출되면 XHR 또는 IIS 구성에서 이상한 것이 아니면 버그 일 가능성이 높습니다.

좀 더 자세히 설명해 주시면 자세히 살펴 보겠습니다.

+0

매트 : 답장을 보내 주셔서 감사합니다. DataSnap 서버를 프록시 생성 코드없이 순수 REST 서버로 호출합니다. 예를 들어 XMLHttpRequest를 직접 사용하고 있습니다 (프록시 생성 serverMethods() 함수를 사용하지 않고 있습니다). 이 방법을 사용하면 OnUserAuthenticate는 모든 서버 메서드 호출마다 한 번 호출됩니다 (단, 브라우저 세션의 첫 번째 호출에서 두 번 호출되는 경우는 예외입니다). 내 질문을 편집하고 XMLHttpRequest 호출을 추가했습니다. –

+0

Mat : 응답 헤더에서 세션 ID를 읽고 후속 요청의 헤더를 반환해야한다는 인상을 받았습니다. 나는 현재 그것을하고 있지 않으며 그것을 조사 할 것입니다. –

+0

매트 : 입력 및 링크에 다시 한 번 감사드립니다. 세션 ID를 캡처하여 이후의 DataSnap 서버 호출에서 반환하는 비동기 호출을 포함하도록 내 질문을 수정했습니다. 물론이 코드는 dssessionexpires Pragma 값을 검사하지 않지만 새로운 값이 나오면 새로운 세션 ID를 캡처합니다. 이제 OnUserAuthenticate (사용자 이름이나 암호가없는 첫 번째 호출과 두 번째 호출) 호출이 두 번 발생하지만 후속 서버 메서드 호출은 OnUserAuthenticate를 트리거하지 않습니다. –

관련 문제