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

如何配置React应用实现点击链接后触发Keycloak登录

问题描述

我用create-react-app创建了一个React应用,配置了简单路由,期望实现以下流程:用户进入首页后点击按钮,跳转到Keycloak登录界面,登录完成后进入UserPage。我已在UserPage中按照官方文档配置了keycloak-js,但未达到预期效果,请问该如何实现这一流程?

现有代码

App.js

import {BrowserRouter, Routes, Route} from 'react-router-dom';
import './App.css';
import Homepage from './pages/Homepage';
import UserPage from './pages/UserPage';
import ErrorPage from './pages/ErrorPage';

function App() {
  return (
    <div className="App">
      <BrowserRouter>
        <Routes>
          <Route index element={<Homepage/>}/>
          <Route path="/home" element={<Homepage/>}/>
          <Route path="/login" element={<UserPage/>}/>
          <Route path="*" element={<ErrorPage/>}/>
        </Routes>
      </BrowserRouter>
    </div>
  );
}

export default App;

UserPage.js(Keycloak配置位置)

import Header from "../components/Header";
import React from 'react';
import Keycloak from 'keycloak-js'

const kcConfig = {
  "url": "http://localhost:8080",
  "realm": "react-realm",
  "clientId": "react-client"   
}
const kc = new Keycloak(kcConfig);

try {
  const authenticated = await kc.init({onLoad: 'login-required', pkceMethod: 'S256', checkLoginIframe: false});
  console.log(`User is ${authenticated ? 'authenticated' : 'not authenticated'}`);
} catch (error) {
    console.error('Failed to initialize adapter:', error);
}

function UserPage() {
  return (
    <div>
        <Header/>
        <h2>Página do usuário</h2>
        <p>Aqui estarão informações do usuário</p>
        <button><a href="/">Voltar</a></button>
    </div>
  )  
}

export default UserPage
解决方案

1. 修复Keycloak初始化错误

你的代码存在两个核心问题:

  • await 不能直接在组件外部使用,必须包裹在async函数内
  • Keycloak初始化逻辑放在组件外部,会在组件加载前执行,不符合React生命周期规范

修改后的UserPage.js:

import Header from "../components/Header";
import React, { useEffect, useState } from 'react';
import Keycloak from 'keycloak-js'

const kcConfig = {
  "url": "http://localhost:8080",
  "realm": "react-realm",
  "clientId": "react-client"   
}
const kc = new Keycloak(kcConfig);

function UserPage() {
  const [isAuthenticated, setIsAuthenticated] = useState(false);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    const initKeycloak = async () => {
      try {
        const authenticated = await kc.init({
          onLoad: 'login-required', 
          pkceMethod: 'S256', 
          checkLoginIframe: false,
          redirectUri: window.location.origin + '/login' // 需与Keycloak客户端配置的回调地址一致
        });
        setIsAuthenticated(authenticated);
        console.log(`User is ${authenticated ? 'authenticated' : 'not authenticated'}`);
      } catch (error) {
        console.error('Failed to initialize adapter:', error);
      } finally {
        setLoading(false);
      }
    };

    initKeycloak();
  }, []);

  if (loading) {
    return <div>加载中...</div>;
  }

  return (
    <div>
        <Header/>
        <h2>用户页面</h2>
        <p>这里将显示用户信息</p>
        <button><a href="/">返回首页</a></button>
        <button onClick={() => kc.logout()}>登出</button>
    </div>
  )  
}

export default UserPage

2. 调整路由与首页逻辑

  • 首页按钮直接跳转至/login路由,onLoad: 'login-required'会自动触发Keycloak登录流程
  • 确保Keycloak客户端配置的Valid Redirect URIs包含http://localhost:3000/login(你的React应用地址),否则登录后会被拒绝回调

首页组件示例(Homepage.jsx):

import { Link } from 'react-router-dom';

function Homepage() {
  return (
    <div>
      <h1>首页</h1>
      <Link to="/login">
        <button>登录进入用户页面</button>
      </Link>
    </div>
  );
}

export default Homepage;

3. 可选:添加路由保护

如果希望未登录用户无法直接访问UserPage,可创建路由保护组件:

// components/ProtectedRoute.jsx
import React, { useEffect, useState } from 'react';
import { Navigate } from 'react-router-dom';
import Keycloak from 'keycloak-js';

const kcConfig = {
  "url": "http://localhost:8080",
  "realm": "react-realm",
  "clientId": "react-client"   
};
const kc = new Keycloak(kcConfig);

const ProtectedRoute = ({ children }) => {
  const [isAuthenticated, setIsAuthenticated] = useState(null);

  useEffect(() => {
    const checkAuth = async () => {
      try {
        const authenticated = await kc.init({
          onLoad: 'check-sso',
          pkceMethod: 'S256',
          checkLoginIframe: false
        });
        setIsAuthenticated(authenticated);
      } catch (error) {
        console.error('Auth check failed:', error);
        setIsAuthenticated(false);
      }
    };

    checkAuth();
  }, []);

  if (isAuthenticated === null) {
    return <div>验证中...</div>;
  }

  return isAuthenticated ? children : <Navigate to="/" />;
};

export default ProtectedRoute;

修改App.js,用保护组件包裹UserPage:

import {BrowserRouter, Routes, Route} from 'react-router-dom';
import './App.css';
import Homepage from './pages/Homepage';
import UserPage from './pages/UserPage';
import ErrorPage from './pages/ErrorPage';
import ProtectedRoute from './components/ProtectedRoute';

function App() {
  return (
    <div className="App">
      <BrowserRouter>
        <Routes>
          <Route index element={<Homepage/>}/>
          <Route path="/home" element={<Homepage/>}/>
          <Route path="/login" element={
            <ProtectedRoute>
              <UserPage/>
            </ProtectedRoute>
          }/>
          <Route path="*" element={<ErrorPage/>}/>
        </Routes>
      </BrowserRouter>
    </div>
  );
}

export default App;

内容的提问来源于stack exchange,提问作者Felipe Mastromauro Corrêa

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 19:05:29