HTTP重定向后从URL中删除哈希标识

5
我刚在一个网站上添加了一个功能,允许用户使用Facebook登录。作为身份验证工作流程的一部分,Facebook会将用户转发到我的网站上的回调URL,例如以下内容。
https://127.0.0.1?facebook-login-callback?code.....#_=_
请注意结尾处的 #_=_(这不是身份验证数据的一部分,Facebook似乎没有明确原因添加这个)
在后端接收请求后,我验证凭据,为用户创建一个会话,然后使用HTTP响应中的Location头将他们转发到主站点。
我通过浏览器开发人员工具检查HTTP响应,并确认已设置位置标头为。
Location: https://127.0.0.1/
问题是,在转发后出现在浏览器地址栏中的URL为https://127.0.0.1/#_=_
我不希望用户看到这个结尾字符串。如何确保在将用户重定向到新URL时删除它?
我测试的所有浏览器都存在此问题。 Chrome,Firefox,Safari和其他一些浏览器。
我知道其他主题中有类似的问题已得到解答,但是这个工作流程中没有jquery或javascript,所有登录回调的处理都在后端代码中进行。
HTTP/1.1 302 Found
Server: nginx/1.19.0
Date: Sun, 28 Nov 2021 10:44:30 GMT
Content-Type: text/plain; charset="UTF-8"
Content-Length: 0
Connection: keep-alive
Location: https://www.facebook.com/v12.0/dialog/oauth?client_id=XXX&redirect_uri=https%3A%2F%2Fmike.local%2Ffacebook-login-callback&state=XXXX

2 用户接受,Facebook将他们重定向到mike.local/facebook-login-callback

HTTP/3 302 Found
location: https://mike.local/facebook-login-callback?code=XXX&state=XXX#_=_
3 后端处理用户转发的Facebook标记,并为用户创建会话,然后将它们转发到 mike.local。如下所示,我不会向 Location HTTP 头中添加 #_=_。请注意该行末尾的有害字符#_=_
HTTP/1.1 302 Found
Server: nginx/1.19.0
Date: Sun, 28 Nov 2021 10:44:31 GMT
Content-Type: text/plain; charset="UTF-8"
Content-Length: 0
Connection: keep-alive
Location: https://mike.local/
Set-Cookie: s=XXX; Path=/; Expires=Fri, 01 Jan 2038 00:00:00 GMT; SameSite=None; Secure;
Set-Cookie: p=XXX; Path=/; Expires=Fri, 01 Jan 2038 00:00:00 GMT; SameSite=Strict; Secure;
4 用户访问 mike.local 网站时,发现 URL 后面有一个尾随的 #_=_。我在 Firefox、Chrome、Safari 和 Edge 中观察到了这种情况。

URL结尾出现神秘字符

我通过 Firefox 检查控制台确认没有发送任何其他 HTTP 请求。换句话说,我可以确定 3 是从我的网站发送给用户的最终 HTTP 响应。


如果您将用户重定向到新位置,则应删除“#hash”部分。 您确定您自己的前端不会干扰此URL吗? - Evert
是的。绝对确定。 - Mike
2个回答

8
根据RFC 7231 §7.1.2

如果3xx(重定向)响应中提供的Location值没有片段组件,则用户代理必须将重定向处理为如果该值继承了用于生成请求目标的URI引用的片段组件,则重定向将继承原始引用的片段(即,重定向继承原始引用的片段(如果有))。

如果Facebook将您重定向到带有片段标识符的URI,则该片段标识符将附加到您的重定向目标。(这不是我很赞同的设计;从语义上讲,忽略起始者的片段标识符对于HTTP 303重定向是有意义的,这是更好地适合此工作流程的逻辑。它就是它。)

最好的方法是通过JavaScript代码片段清除目标页面上的片段标识符:

<script async defer type="text/javascript">
    if (location.hash === '#_=_') {
        if (typeof history !== 'undefined' &&
            history.replaceState &&
            typeof URL !== 'undefined')
        {
            var u = new URL(location);
            u.hash = '';
            history.replaceState(null, '', u);
        } else {
            location.hash = '';
        }
    }
</script>

另外,您可以使用元刷新/ Refresh HTTP头部来重定向,因为该方法不会保留片段标识符:

<meta http-equiv="Refresh" content="0; url=/">

假设您还应该包括一个指向目标页面的手动链接,以便那些未实现“刷新”功能的客户端。但如果你问我个人会怎么做:不要管这个可怜的东西。无用的片段标识符并没有什么害处,而这种愚蠢的微观管理并不值得为了相当次要的地址栏美学而颠覆整个互联网标准(使用更脆弱、非标准的重定向方法;将另一个多余的JavaScript代码塞给用户)。正如《上帝之屋》所说:“提供良好的医疗保健服务就是尽可能少做事情。”

1
不是完整的答案,但提供了一些更广泛的架构方面的参考信息,以补充我赞同的上述答案。
授权服务器
如果您启用了AS来管理与Facebook的连接,则您的应用程序无需处理此问题。
AS可以处理许多深层次的外部身份验证问题,以将复杂性从应用程序外部化。
单页应用程序
SPA会更好地控制处理登录响应,例如我这个代码中使用的history.replaceState。
安全性
如果具备正确的架构设计,SPA与网站一样安全—请参阅此文章。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接