Как мне обойти междоменную безопасность window.opener

Я только что узнал, что window.opener недоступен в окне, открытом через window.open если новый URL-адрес междоменный, в IE. Как я могу определить открыватель окна в IE

Это произойдет, если окно запускается в моем домене, покидает его, а затем возвращается в мой домен. Я пытаюсь создать социальную регистрацию (Facebook, Google и т. Д.) Во всплывающем окне. Когда он завершится, он должен закрыть новое окно и перенаправить открыватель.

Я знаю, что Soundcloud справляется с этим, но я понятия не имею, как. Я вижу, как URL меняется с их на Facebook, а затем закрывается.

После перенаправления обратно на мой сайт от третьей стороны я запускаю это:

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

Он выдает предупреждение в IE, хотя изначально это окно было моим доменом, которое затем перенаправлялось в FB, а затем перенаправлялось обратно ко мне. Я подумал, может, так как я открываю свой сайт и сразу же перенаправляю из PHP, что может быть проблемой. Однако даже когда я открыл свой сайт, сделал window.location.href = 'facebookssite.com' он все еще жаловался при возвращении.

НОТА

Регистрация в социальных сетях не работает для Google, FB и т. Д. В iframe, Я считаю, что они запрещают их по соображениям безопасности.

5 ответов

Решение

Сделай это наоборот. Отслеживайте состояние дочернего всплывающего окна в главном (открывающем) окне, и вы можете легко узнать, когда дочернее окно было перемещено обратно к вашему домену, чтобы вы могли "поговорить" с ним снова. Но не закрывайте дочернее окно само по себе. Позвольте открывающему окну получить результат из дочернего окна, а затем закройте его.

Например, 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>

Протестировано с IE10.

По соображениям безопасности, window.opener удаляется при перенаправлении на другой домен. Браузер не удосуживается восстановить window.opener когда ты вернешься. В вашем случае вы можете попробовать:

1) Выполните аутентификацию внутри iframe, если это возможно, вместо использования перенаправления.

2) В вашем случае я вижу, что вам нужно отправить данные обратно в родительское окно. Вы можете попробовать это вместо этого:

В открывшемся окне просто сохраните data и закройте нормально.

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

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

Ваше родительское окно имеет доступ к вашему открытому окну и может обрабатывать его close событие:

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) Обходной путь: используйте таймер на родительской странице, чтобы проверить наличие closed собственность openedWindow

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

   }
},1000);

4) Другое решение, использующее localStorage, так как вы находитесь в одном домене. Ваша родительская страница может прослушать событие

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

}, true);

Ваш открытый код окна:

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

if (localStorage){
   localStorage.setItem(JSON.stringify(data));
}
window.close();
  1. Из вашего iframe, веб-страницы на yoursite.com... откройте новое окно на yoursite.com
  2. Окно перенаправляется в Google, Twitter, что угодно
  3. После этого перенаправление OAuth возвращает окно на страницу на вашем сайте.
  4. Новое окно, поскольку оно имеет тот же источник, что и открывшая его страница, может взаимодействовать через window.open.

Используйте localStorage или IndexedDB для связи между окнами, в которых отображаются документы из одного домена, но которые не имеют ссылок друг на друга.

Просто используйте высокоскоростной таймер, проверяющий данные, сохраняя другой фрагмент данных для подтверждения получения, и другое окно может найти его и закрыть.

Короче говоря - вы используете localStorage для передачи команд и даже можете иметь библиотеку для этого, удалять команды после их выполнения и отправлять возвращаемые значения.

Вы можете использовать window.postMessage(), который предусмотрен именно для этого сценария.

Пояснение: https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage

В моей компании у нас разные домены, и есть случай, когда сайт интрасети должен получить наш общедоступный веб-сайт (чтобы, наконец, избавиться от обслуживания дублированных данных). Вдохновленный в Ben Vinegar, я пришел к этому решению, простому решению, избегая:

Звоните на веб-страницу домена (в моем случае с тем же именем, что и внешнее)

местный 'getInfo.php'

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

Внешнийвозврат getInfo.php

 <?php  
    echo '<script>window.opener.manageDisplay('.$getRes.','.$isOK.');</script>';
    if($auto_close){ echo "<script>window.close();</script>"; }
  ?>
Другие вопросы по тегам