You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 13:32:45