Keycloak 在硬页面刷新后就像未初始化一样
Posted
技术标签:
【中文标题】Keycloak 在硬页面刷新后就像未初始化一样【英文标题】:Keycloak acts as if its uninitialized after a hard page refresh 【发布时间】:2022-01-18 04:06:24 【问题描述】:首先,提前感谢任何阅读我的问题和 cmets 的人。我有一个使用来自`@react-keycloak/web 的keycloak-js
和ReactKeycloakProvcer
的CRA 应用程序。当您第一次加载应用程序页面并登录时,keycloak 已正确初始化并正常运行。提供者以非常标准的方式获取 KC 的实例。
import keycloak from './authentication/keycloak'
const KeycloakProviderBlock = (children) =>
return (
<ReactKeycloakProvider authClient=keycloak initOptions=onLoad: 'login-required'>
children
</ReactKeycloakProvider>
);
;
稍后在我的 axios 包装器中,我将 KC 令牌拉出以添加到所有请求中作为不记名令牌,如下所示:
import keycloak from "./authentication/keycloak";
const authenticated = keycloak;
if (authenticated)
client.defaults.headers.common =
...client.defaults.headers.common,
Authorization: `Bearer $keycloak.token`,
;
else
logger.error("Request client used before KeyCloak initialized");
我的 keycloak 文件只返回一个新的 KC 实例 --> /authentication/keycloak.js 的内容
import Keycloak from "keycloak-js";
const keycloak = new Keycloak(
realm: process.env.REACT_APP_KEYCLOAK_REALM,
url: process.env.REACT_APP_KEYCLOAK_URL,
clientId: process.env.REACT_APP_KEYCLOAK_CLIENT,
)
export default keycloak
在用户硬刷新页面之前,一切都会正常运行。当页面重新加载时,KC 对象上不存在 keycloak.authenticated,因此所有 HTTP 调用都会失败,因为没有 Bearer 令牌。
我正在使用 keycloak-js 版本 15.0.2。任何/所有想法表示赞赏。
【问题讨论】:
【参考方案1】:我想出了如何解决这个问题,并想我会发布答案,以防它帮助其他人。事实证明,当页面刷新时,KC 从 cookie 中恢复会话信息所需的时间比运行代码所需的时间要长。因此,当页面重新加载时,它试图在 KC 有机会验证用户确实登录之前到达后端时存在竞争条件。事实证明,KeycloakProvider 会发出事件并告诉您何时刷新令牌。事件未触发,因为我将 KCProvider 包装在 JSX 组件中,因此事件未正确绑定。我删除了不必要的块,事件开始触发。从那里开始,很容易显示 Loading throbber 并阻止其余组件呈现,直到提供者实际获得 onReady 事件。新代码如下所示:
在 App.js 中
// Keycloak
onKeycloakEvent = (event, error) =>
console.log('onKeycloakEvent', event, error)
console.log(`Keycloak Event $event`);
if(event && event === 'onReady')
this.setState(keycloakReady: true)
onKeycloakTokens = (tokens) =>
console.log('onKeycloakTokens', tokens)
... 在 Render 中将函数传递给提供者:
<ReactKeycloakProvider authClient=keycloak initOptions=onLoad: 'login-required'
keycloak=keycloak
onEvent=this.onKeycloakEvent
onTokens=this.onKeycloakTokens>
<SplashScreen keycloakReady=keycloakReady>
....
</SplashScren>
</ReactKeycloakProvder>
然后在 SplashScreen 中仅在 KC 准备好时渲染子项:
import React, Component, PureComponent, ReactChildren from "react";
import LoadingSpinner from "../navigation/LoadingSpinner";
type PassedProps =
keycloakReady: boolean;
class SplashScreen extends PureComponent<PassedProps, any>
constructor(props: PassedProps)
super(props);
render()
console.log(`SplashScreen keycloak ready $this.props.keycloakReady`);
if(!this.props.keycloakReady)
return <LoadingSpinner/>
else
return this.props.children
export default SplashScreen
【讨论】:
以上是关于Keycloak 在硬页面刷新后就像未初始化一样的主要内容,如果未能解决你的问题,请参考以下文章