Фрагмент URL потерян как часть аутентификации токена SAML; Обходной путь / стандартная схема?

Некоторые протоколы аутентификации веб-приложений (такие как WS-Federation и протокол SAML, т. Е. Так называемые "пассивные" протоколы и, по-видимому, также аутентификация ASP.NET Forms, см. Этот вопрос Stackru, и AppEngine, см. Этот комментарий об ошибке GWT) теряют оригинальный фрагмент URL, то есть часть после знака #.

Что происходит примерно так: в чистом браузере (поэтому нет кэшированной информации / файлов cookie / данных для входа) я открываю URL (1) http://example.com/myapp/somepage?some=parameter. Это делает запрос браузера (2) http://example.com/myapp/somepage?some=parameter, сервер перенаправляет меня к моему провайдеру идентификации (включая URL (2) в запросе аутентификации), и в конечном итоге я перенаправлен назад, откуда я пришел, это URL (2): это единственный URL, о котором знает сервер. Но я хотел перейти к URL (1), и фрагмент URL ("якорь") был утерян по пути, фактически уже на первом этапе.

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

Я знаю, что в соответствии со спецификациями браузер запрашивает (2) с сервера, когда я перехожу к (1), что приводит к этому ограничивающему фрагменты ограничению протокола SAML, WS-Federation и т. Д. Мой вопрос: как сделать Я работаю вокруг этого ограничения?

Очевидный обходной путь - избегать фрагментов URL, как предлагается в этом ответе. Однако для нашего конкретного веб-приложения это нехорошо, поскольку мы используем закладки URL-фрагментов в нашем одностраничном GWT-приложении, чтобы убедиться, что навигация в нашем приложении не приводит к перезагрузке страницы.

Мой вопрос: какие есть другие обходные пути или стандартные шаблоны для этой ситуации?

(Меня особенно интересует решение протокола GWT + SAML.)

2 ответа

У вас есть два варианта:

  • избегать использования location.hash (используйте HTML5 pushState вместо этого, по крайней мере, в браузерах, которые его поддерживают; и / или предложить способ создания постоянных ссылок в вашем приложении - это делает группа Google)

  • сделать перенаправление с помощью JavaScript. Т.е. вместо отправки перенаправления с сервера отправьте пустую HTML-страницу с каким-нибудь скриптом, который принимает полный URL-адрес (с хэшем) и выполняет перенаправление, используя location.assign() или же location.replace(), Если вам повезет (в зависимости от серверов), вы будете перенаправлены на этот полный URL-адрес после аутентификации.

Конечно, вы можете сделать и то и другое: если ссылка является глубокой ссылкой в ​​приложение, то выполнить перенаправление (т. Е. Предположить, что хеша нет), в противном случае отправить страницу с JS, чтобы убедиться, что вы не потеряете состояние, присутствующее в хэш

И, наконец, очевидное третье решение, далеко не идеальное: не делайте ничего и пытайтесь обучить пользователей тому, что, когда им нужно (повторно) пройти аутентификацию, они должны повторно вставить URL-адрес или повторно щелкнуть ссылку или повторно щелкнуть закладка.

Согласно RFC 1738 теги привязки не отправляются клиентом на сервер при запросе ресурса.

Якорные теги используются для определения местоположения внутри ресурса, а не другого ресурса на сервере. Чтобы идентифицировать местоположение в ресурсе, клиент должен извлечь полный ресурс с сервера, и этот процесс не должен включать передачу информации о фрагменте (поскольку это ничего не значит для сервера).

Если вы хотите отправить символ фрагмента (#) на сервер, то вам необходимо закодировать его в строке запроса, или клиент (браузер) просто проигнорирует этот раздел URL-адреса при отправке запроса на сервер.

РЕДАКТИРОВАТЬ:

Я не знаю никакого реального решения, но чтобы обойти эту проблему, вам нужно сохранить свой полный обратный URL (с тегами привязки) где-нибудь на стороне клиента, потому что сервер ничего не знает об привязках. Для этого вы можете использовать SessionStorage ( http://www.w3schools.com/html/html5_webstorage.asp) для временного хранения ReturnUrl до завершения процесса входа в систему. Обратите внимание, что он не будет поддерживаться в старых браузерах (например, <= IE7).

В этом случае обходной путь будет выглядеть примерно так:

<script>
    if(typeof(sessionStorage) == 'undefined')
    {
        sessionStorage = {
            getItem: function(){},
            setItem: function(){}
        };
    }

    window.onload = function ()
    {
        var key = 'ReturnUrl';

        //try to get last returnUrl with anchors
        var returnUrl = sessionStorage.getItem(key);

        //if we got something, do the navigation
        if(returnUrl !== undefined && returnUrl !== document.URL)
        {
            //clean it up
            sessionStorage.setItem(key, null);
            //navigate to last URL
            window.location = returnUrl;
        }
        else
        {
            //store url 
            sessionStorage.setItem(key, document.URL);
        }
    }
</script>

PS. Обнажись со мной, если есть какие-то синтаксические ошибки, потому что я записал это из головы и не пробовал.

Другие вопросы по тегам