Keycloak redirect_fragment 与 react-router hashRouter 冲突

Keycloak redirect_fragment conflicts with react-router hashRouter

我 运行 在我的应用程序用户使用 Keycloak 进行身份验证后发生的重定向问题。

我的应用程序使用 react-router hashRouter。当初始重定向发生时,我得到一个看起来像这样的 redirect_fragment:

http://localhost:3000/lol.html?redirect_fragment=%2F&redirect_fragment=%2Fstate%3D1c5900ee-954f-4532-b01c-dcf5d88f07a2%26code%3DKZNXVqQCcIXTCFu2ZIkx4quXa6zJb59zGKpNIhZwfNo.d2786d1e-67cd-437f-a873-bad49126bad4&redirect_fragment=%2Fstate%3D51a9cb44-b80a-4c14-8f3d-f04dfdb84377%26code%3Dp5cKQ7xVCR_n1s4ucXZTSE3O1T5lwNri_PBKD07Mt1Y.63364a83-f04f-4e64-a33e-faf00f6cd4ff&redirect_fragment=%2Fstate%3D05155315-ab60-4990-8d4e-444c7cce9748%26code%3DBxxpf_uMB28rKAQ6MXFTTrL9RE4rC3UtwCMXLu_K1Zo.4ce56da0-8e52-47e3-a0f2-4f982599bb98#/state=f3e362e4-c030-40ac-80df-9f9882296977&code=8HHTgd3KdlfwcupXR_5nDV0CqZNPV1xdCu3udc6l5xM.97b3ea71-366a-4038-a7ce-30ac2f416807

URL 从那里不断增长。我已经阅读了一些帖子,这些帖子表明从 keycloak 重定向可能与通过 location.hash 的客户端路由有问题...任何想法将不胜感激!

我想我明白了!

如果我使用 'noslash' hashRouter 而不是包含斜杠的默认值,重定向循环似乎会停止。

我的 URL 看起来像这样:localhost:3000/lol.html#client/side/route

而不是这个:localhost:3000/lol.html#/client/side/route

重定向现在似乎在一次重定向后适当终止,但现在我 运行 陷入了另一个问题,我的路由的哈希部分没有被 react-router 接受...

编辑:我想出了第二个问题

react-router 在 window.location 周围创建一个包装器,它用来告诉 "page" 它当前在哪个客户端。 我发现这个包装器与 window.location 不同步。

检查这个控制台输出。这是在重定向解决后立即采取的(并且页面是空白的):

历史路径名是 /state=aon03i-238hnsln-soih930-8hsdlkh9-982hnkui-89hkgyq-8ihbei78-893hiugsu

历史哈希为(空)

window.location 路径名是 /lol.html

window.location 哈希是 #users/1

history.pathname 中的 state=blah-blah-blah 是 keycloak 在验证后发回的重定向 url 的一部分。您会注意到 window.location 已更新为正确的路径/散列,但该历史记录似乎落后 URL。也许keycloak直接修改window.location来执行这个重定向?

我尝试使用 history.push(window.location.hash) 推送哈希片段并更新 React 路由器,但出现错误 "this entry already exists on the stack"。由于它显然不在位置堆栈的顶部,这让我相信 react-router 将 window.location 与其内部位置进行比较以找出它最终在哪里。那么我是如何解决这个问题的呢?

我改用了history.replace(),它只是用新值替换堆栈顶部的条目,而不是将新条目压入堆栈。这也是有道理的,因为我们不希望在浏览器中导航 "back" 的用户返回到那个 /state=blah-blah-blah url <-- replace 会从历史堆栈中删除该条目。

最后一块:react-router history.location,与 window.location 一样,同时具有路径名和哈希组件。 HashRouter 使用 history.location.pathname 组件来跟踪浏览器中散列后的客户端路由。 window.location 中的等效项存储在 window.location.hash 中,因此我们将使用它作为传递给 history.replace() 的值而不是 window.location.pathname。这让我有些困惑,但仔细想想就明白了。

react-router history 也使用前缀 / 而不是前缀 # 来跟踪其当前路由,因为它只是像对待任何正常的 URL 一样对待它。在调用 history.replace() 之前,我需要使用 window.location.hash,用 / 替换前导散列,然后传递该值 history.replace()

const slashPath = window.location.hash.replace('#', '/'); history.replace(slashPath);

哇哦!