在TypeScript文件index.tsx中集成Keycloak遇阻,求指导
Keycloak集成问题:未登录跳转登录页,登录后进入UI
我在index.tsx中集成Keycloak时遇到错误,希望实现未登录时自动跳转到Keycloak登录页,登录后进入UI界面,着陆页为layout.tsx。以下是我的代码,求指导正确的集成方式。
index.tsx代码
import React from "react"; import ReactDOM from "react-dom/client"; import { createHashRouter, RouterProvider } from "react-router-dom"; import { initializeIcons } from "@fluentui/react"; import KeycloakUserService from "./components/Login/KeycloakUserService"; import "./index.css"; import Layout from "./pages/layout/Layout"; import Chat from "./pages/chat/Chat"; initializeIcons(); const router = createHashRouter([ { path: "/", element: <Layout />, children: [ { index: true, element: <Chat /> }, { path: "qa", lazy: () => import("./pages/oneshot/OneShot") }, { path: "*", lazy: () => import("./pages/NoPage") } ] } ]); ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render( <React.StrictMode> <RouterProvider router={router} /> </React.StrictMode> ); KeycloakUserService.initKeycloak(router);
KeycloakUserService.js代码
import Keycloak from "keycloak-js"; const keycloakJson = { "realm": "eMigration", "url": `https://1ansah.com/auth/`, "ssl-required": "none", // "clientId": process.env.REACT_APP_KEYCLOAK_RESOURCE, // "resource": process.env.REACT_APP_KEYCLOAK_RESOURCE, "public-client": true, "confidential-port": 0 } const _kc = new Keycloak(keycloakJson); /** * Initializes Keycloak instance and calls the provided callback function if successfully authenticated. * * @param onAuthenticatedCallback */ const initKeycloak = (onAuthenticatedCallback) => { _kc .init({ onLoad: "login-required", silentCheckSsoRedirectUri: window.location.origin + "/silent-check-sso.html", pkceMethod: "S256" }) .then((_authenticated) => { onAuthenticatedCallback(); }) .catch(console.error); }; const doLogin = _kc.login; const doLogout = _kc.logout; const getToken = () => _kc.token; const getEmail = () => _kc.idTokenParsed.email; const isLoggedIn = () => !!_kc.token; const updateToken = (successCallback) => _kc.updateToken(5).then(successCallback).catch(doLogin); const getUsername = () => _kc.tokenParsed?.preferred_username; const hasRole = (roles) => roles.some((role) => _kc.hasRealmRole(role)); const getRoles = () => _kc.tokenParsed?.roles; const getUserID = () => _kc.tokenParsed?.sub; const isAuthenticated = () => _kc.authenticated; const getGroups = () => _kc.tokenParsed?.groups; const KeycloakUserService = { initKeycloak, doLogin, doLogout, getEmail, isLoggedIn, getToken, updateToken, getUsername, hasRole, getRoles, getUserID, isAuthenticated, getGroups }; export default KeycloakUserService;
解决方案
1. 调整Keycloak初始化时机
当前代码先渲染路由再初始化Keycloak,会导致未认证时路由已加载,无法正确跳转。需先完成Keycloak初始化,再渲染应用:
修改index.tsx为:
import React, { useState, useEffect } from "react"; import ReactDOM from "react-dom/client"; import { createHashRouter, RouterProvider } from "react-router-dom"; import { initializeIcons } from "@fluentui/react"; import KeycloakUserService from "./components/Login/KeycloakUserService"; import "./index.css"; import Layout from "./pages/layout/Layout"; import Chat from "./pages/chat/Chat"; initializeIcons(); const router = createHashRouter([ { path: "/", element: <Layout />, children: [ { index: true, element: <Chat /> }, { path: "qa", lazy: () => import("./pages/oneshot/OneShot") }, { path: "*", lazy: () => import("./pages/NoPage") } ] } ]); const App = () => { const [isKeycloakInitialized, setIsKeycloakInitialized] = useState(false); useEffect(() => { KeycloakUserService.initKeycloak(() => { setIsKeycloakInitialized(true); }); }, []); if (!isKeycloakInitialized) { return <div>Loading...</div>; // 初始化加载提示 } return <RouterProvider router={router} />; }; ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render( <React.StrictMode> <App /> </React.StrictMode> );
2. 完善Keycloak配置
取消clientId和resource的注释,确保配置正确(替换为你的实际客户端ID):
const keycloakJson = { "realm": "eMigration", "url": `https://1ansah.com/auth/`, "ssl-required": "none", "clientId": "your-client-id", // 替换为实际客户端ID "resource": "your-client-id", // 与clientId一致 "public-client": true, "confidential-port": 0 }
3. 添加路由守卫(可选但推荐)
在Layout组件中检查登录状态,防止未认证用户直接访问:
// Layout.tsx import React, { useEffect } from "react"; import KeycloakUserService from "../components/Login/KeycloakUserService"; import { useNavigate } from "react-router-dom"; const Layout = () => { const navigate = useNavigate(); useEffect(() => { if (!KeycloakUserService.isAuthenticated()) { KeycloakUserService.doLogin(); } }, []); // 你的Layout内容 return <div>Layout Content</div>; }; export default Layout;
4. 配置silent-check-sso.html
在项目public目录下创建silent-check-sso.html文件,内容如下:
<!DOCTYPE html> <html> <body> <script> parent.postMessage(location.href, location.origin); </script> </body> </html>
5. 处理TypeScript类型(可选)
将KeycloakUserService.js改为KeycloakUserService.ts,添加类型声明:
import Keycloak, { KeycloakInstance } from "keycloak-js"; const keycloakJson = { // 配置内容 }; const _kc: KeycloakInstance = new Keycloak(keycloakJson); // 其余代码不变,类型会自动推导
内容的提问来源于stack exchange,提问作者sumita Raj
相关产品推荐
相关产品推荐

