2013-09-05 14 views
26

Właśnie się dowiedziałem, że window.opener nie jest dostępny w oknie otwartym przez window.open, jeśli nowy adres URL jest między domenami, w IE. How do I detect window opener in IEJak obejść okno window.open zabezpieczeń międzydomenowych

Stanie się tak, jeśli okno zaczyna się w mojej domenie, zostawia je, a następnie wraca do mojej domeny. Próbuję utworzyć rejestrację społecznościową (facebook, google, itp.) W wyskakującym okienku. Po zakończeniu należy zamknąć nowe okno i przekierować otwieracz.

Wiem, że Soundcloud to ciągnie, ale nie mam pojęcia jak. Widzę zmianę adresu URL z ich na Facebooku, a następnie zamykam.

Po przekierowanie z powrotem do mojej strony z 3rd party biegnę to:

var data = { 
    type : 'complete', 
    destination : '<?= $destination; ?>' 
}; 
if (window.opener) { 
    window.opener.postMessage(JSON.stringify(data), '*'); 
    window.close(); 
} 
else { 
    alert("Unable to find window"); 
} 

To alarmuje w IE, mimo że okno było pierwotnie moja domena, która następnie przekierowany na FB, następnie przekierowany z powrotem do mnie . Myślałem, że od kiedy mogę otworzyć moją stronę i przekierować natychmiast z PHP, może to być problem. Jednak nawet po otwarciu mojej strony, wciąż się skarżyłem po powrocie.

UWAGA

rejestracje społeczne nie pracuję dla Google, FB itp ramach iframe. Uważam, że nie pozwalają im z powodów bezpieczeństwa.

Odpowiedz

25

zrobić to na odwrót. Śledź stan okna podręcznego podrzędnego z okna głównego (otwieracza) i możesz łatwo sprawdzić, kiedy okno podrzędne zostało przeniesione z powrotem do Twojej domeny, aby móc ponownie "porozmawiać" z nim. Ale nie zamykaj okna podrzędnego. Niech okno otwierające uzyska wynik z okna podrzędnego, a następnie zamknij je.

Przykładowo main.html:

<!DOCTYPE html> 
<head> 
<title>main</title> 
<meta http-equiv="X-UA-Compatible" content="IE=edge"/> 
<script> 
window.addEventListener("message", function(ev) { 
    if (ev.data.message === "deliverResult") { 
     alert("result: " + ev.data.result); 
     ev.source.close(); 
    } 
}); 

function Go() { 
    var child = window.open("child.html", "_blank", "height=200,width=200"); 

    var leftDomain = false; 
    var interval = setInterval(function() { 
     try { 
      if (child.document.domain === document.domain) 
      { 
       if (leftDomain && child.document.readyState === "complete") 
       { 
        // we're here when the child window returned to our domain 
        clearInterval(interval); 
        alert("returned: " + child.document.URL); 
        child.postMessage({ message: "requestResult" }, "*"); 
       } 
      } 
      else { 
       // this code should never be reached, 
       // as the x-site security check throws 
       // but just in case 
       leftDomain = true; 
      } 
     } 
     catch(e) { 
      // we're here when the child window has been navigated away or closed 
      if (child.closed) { 
       clearInterval(interval); 
       alert("closed"); 
       return; 
      } 
      // navigated to another domain 
      leftDomain = true; 
     } 
    }, 500); 
} 
</script> 
</head> 
<body> 
<button onclick="Go()">Go</button> 
</body> 

Child.html:

<!DOCTYPE html> 
<head> 
<title>child</title> 
<meta http-equiv="X-UA-Compatible" content="IE=edge"/> 
<script> 
window.addEventListener("message", function(ev) { 
    if (ev.data.message === "requestResult") { 
     // ev.source is the opener 
     ev.source.postMessage({ message: "deliverResult", result: true }, "*"); 
    } 
}); 
</script> 
</head> 
<body> 
<a href="http://www.example.com">Go to example.com</a> 
Then click the browser Back button when ready. 
</body> 

Testowane IE10.

+1

Podoba mi się ten pomysł. Zrobię to, gdy wrócę do biura. –

+0

@Noseratio: Twoje rozwiązanie działa doskonale, jeśli w oknie jest otwarty inny adres URL domeny, ale w jaki sposób możemy zmodyfikować Twój kod, aby poradzić sobie z sytuacją, w której Facebook wewnętrznie uwierzytelnia użytkownika i po prostu otwiera przekierowany adres URL w oknie. W takim przypadku flaga LeftDomain jest fałszywa, mimo że nastąpiło wewnętrzne przekierowanie. –

+0

@dark_shadow, proponuję zadać to jako osobne pytanie i powiązać to z nim. – Noseratio

1
  1. ze swojego iframe, strony internetowej, na yoursite.com ... otwierać nowe okno na yoursite.com
  2. Okno przekierowuje się do Google, Twitter, cokolwiek
  3. Raz zrobione, OAuth przekierować zyski okno do strony, na yoursite.com
  4. nowego okna, ponieważ ma takie samo pochodzenie jak strony, które go otwartym, może komunikować się za pomocą window.open
+0

W jaki sposób nowe okno komunikuje się z otwieraczem? 'window.open ('mysite.com', 'parent')'? Myślę, że rodzic nie byłby tam prawdziwy. Czy muszę po prostu upewnić się, że otwieracz ma identyfikator celu. Już robię 1-3 –

+0

Nie używaj postmessage. Po prostu użyj bezpośredniego dostępu, który możesz zrobić, ponieważ mają one ten sam pochodzenie. 'window.opener.globalFuncInOpenerContext()'. –

+0

Zaktualizowałem moje pytanie. Nie jest nawet wiadomo, że 'window.opener' jest prawdziwy po powrocie do mojej witryny. Zastanawiam się, co może być inne, że nie działa dla ciebie. –

7

z powodu względów bezpieczeństwa, window.opener jest usuwany podczas czerwony poprawianie do innej domeny. Po powrocie przeglądarka nie zadaje sobie trudu przywrócenia wartości window.opener. W twoim przypadku możesz spróbować:

1) Wykonaj uwierzytelnianie wewnątrz elementu iframe, jeśli to możliwe, zamiast przekierowania.

2) W twoim przypadku widzę, że musisz wysłać dane z powrotem do okna nadrzędnego. Możesz spróbować tego zamiast:

W otwartym oknie, zapisz swoją data i zamknij normalnie.

var data = { 
    type : 'complete', 
    destination : '<?= $destination; ?>' 
}; 

window.hasData = true; 
window.data = data; 
window.close(); 

Twoje okno rodzic ma dostęp do otwartego okna i może obsługiwać swój close zdarzenie:

openedWindow.beforeunload = function(){ 
    //here you could access this.data or openedWindow.data because you're on the same domain 
    if (this.hasData){ 
    } 
    //Reason we have this check is because the beforeunload event fires whenever the user leaves your page for any reason including close, submit, clicking a link, ... 
} 

3) obejście: Użyj czasomierza na stronie macierzystej w celu sprawdzenia mieniu closedopenedWindow

setInterval(function(){ 
    if (openedWindow.closed){ 

    } 
},1000); 

4) Innym rozwiązaniem użyciu localStorage jak jesteś w tej samej domenie.Jesteś rodzicem strona może słuchać przypadku

window.addEventListener("storage", function(event){ 

}, true); 

kodzie openedWindow:

var data = { 
    type : 'complete', 
    destination : '<?= $destination; ?>' 
}; 

if (localStorage){ 
    localStorage.setItem(JSON.stringify(data)); 
} 
window.close(); 
+0

Nazwa mojego okna odwołuje się do "social_window". 'social_window.beforeunload = function() {' never fired anything. 'social_window.onbeforeunload = function() {' uruchomiony tylko wtedy, gdy zamknąłem okno zanim nastąpiło przekierowanie do FB/Google. –

+0

@Dave Stein: co powiesz na używanie timera? To rozwiązanie nie jest dobre, ponieważ nie możemy mieć dobrego rozwiązania, ponieważ jest to zachowanie przeglądarki. Wszystko, co możemy zrobić, to znaleźć obejście. –

+0

@Dave Stein: Myślę, że realnym rozwiązaniem jest załadowanie formularza uwierzytelniania wewnątrz iframe, jeśli to możliwe. Dzięki takiemu podejściu nie musimy opuszczać naszej domeny i całkowicie uniknąć tego problemu. –

0

W mojej firmie mamy różne domeny i jest przypadek, w którym strona intranetowa musi uzyskać naszą publiczną stronę internetową (aby w końcu pozbyć się utrzymania powielonych danych). Zainspirowany w Ben Ocet Doszedłem do tego roztworu prostego rozwiązania unikając:

Wezwanie do domeny internetowej (w moim przypadku o tej samej nazwie co jedna zewnętrzna)

lokalnym „getInfo.php

<?php 
     $idSp = (isset($_GET['idSp'])?$_GET['idSp']:null); 
     echo file_get_contents('http://192.168.1.10/folder/getInfo.php?idSp='.$idSp); 
?> 

zewnętrzna powrót 'getInfo.php'

<?php 
    echo '<script>window.opener.manageDisplay('.$getRes.','.$isOK.');</script>'; 
    if($auto_close){ echo "<script>window.close();</script>"; } 
    ?> 
0

Użyj komendy localStorage lub IndexedDB, aby komunikować się między oknami, które wyświetlają dokumenty z tej samej domeny, ale które nie mają ze sobą odniesienia.

Wystarczy mieć szybki programator do sprawdzania danych, zapisując kolejne dane, aby potwierdzić odbiór, a inne okno może je znaleźć i zamknąć.

W skrócie - używasz localStorage do przekazywania poleceń, a nawet możesz mieć bibliotekę, która to robi i usuwa polecenia po ich wykonaniu, a następnie wysyła wartości zwracane.

Powiązane problemy