6

几个 Web 应用程序身份验证协议(如 WS-Federation 和 SAML 协议,即所谓的“被动”协议,显然还有 ASP.NET Forms 身份验证,请参阅此 StackOverflow 问题和 AppEngine,请参阅此 GWT 错误评论)丢失原始的“URL 片段”,即#-符号之后的部分。

发生的情况大致如下:在干净的浏览器中(因此没有缓存的信息/cookies/登录信息)我打开 URL (1) http://example.com/myapp/somepage?some=parameter#somewhere。这使得浏览器请求 (2) http://example.com/myapp/somepage?some=parameter,服务器将我重定向到我的身份提供者(包括身份验证请求中的 URL (2)),最终我被重定向回到我来自的地方,即 URL (2):这是服务器知道的唯一 URL。但是我想转到 URL (1),并且 URL 片段('anchor')一直丢失,实际上已经在第一步中。

这似乎是这些协议的基本限制,因为服务器根本看不到 URL 片段。

我知道它是根据浏览器从服务器请求 (2) 的规范,当我导航到 (1) 时,导致对 SAML 协议、WS-Federation 等的这种片段丢失限制。我的问题是:怎么做我解决了这个限制?

显而易见的解决方法是避免 URL 片段,正如这个答案中所建议的那样。但是,对于我们的特定 Web 应用程序来说,这并不好,因为我们在单页 GWT 应用程序中使用了可收藏的 URL 片段,以确保我们的应用程序中的导航不会导致页面重新加载。

我的问题:对于这种情况,还有哪些其他解决方法或标准模式?

(我对 GWT + SAML 协议解决方案特别感兴趣。)

4

2 回答 2

1

你基本上有两个选择:

  • 避免使用location.hash(使用 HTML5pushState代替,至少在支持它的浏览器上;和/或提出一种在您的应用程序中生成永久链接的方法- Google Groups 这样做)

  • 使用 JavaScript 进行重定向。即不是从服务器发送重定向,而是发送一个带有一些脚本的空 HTML 页面,该脚本采用完整的 URL(带有hash)并使用location.assign()or进行重定向location.replace()。运气好的话(取决于服务器),您将在身份验证后被重定向到该完整 URL。

你当然可以两者都做:如果链接是应用程序的深层链接,则进行重定向(即假设没有hash),否则发送一个带有 JS 的页面以确保你不会丢失任何存在哈希

最后是明显的第三种解决方案,远非理想:不要做任何事情,并尝试教育用户,当他们需要(重新)进行身份验证时,他们应该重新粘贴 URL 或重新单击链接或重新单击书签。

于 2013-12-11T17:05:30.427 回答
0

根据RFC 1738,客户端在请求资源时不会将锚标签发送到服务器。

锚标记用于标识资源中的位置,而不是服务器上的不同资源。为了识别资源中的位置,客户端需要从服务器获取完整的资源,并且此过程不需要涉及有关片段的信息的传输(因为它对服务器没有任何意义)。

如果您确实希望将片段字符 (#) 发送到服务器,那么您需要在查询字符串中对其进行编码,否则客户端(浏览器)在将请求发送到服务器。

编辑:

我不知道任何真正的解决方案,但要解决此问题,您需要将完整的返回 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。如果有一些语法错误,请多多包涵,因为我是从头顶写下来的,没有尝试过。

于 2013-12-11T15:11:24.067 回答