/** * Phase 3: Keycloak SSO 設定 * * 功能: * 1. 填寫 Keycloak 連接資訊 * 2. 測試 Keycloak 連接 * 3. 將設定寫入 .env 檔案 */ 'use client' import { useState, useEffect } from 'react' import { useRouter } from 'next/navigation' interface KeycloakConfig { url: string realm: string admin_username: string admin_password: string } interface TestResult { success: boolean message: string keycloak_version?: string realm_info?: string } export default function Phase3Keycloak() { const router = useRouter() const [config, setConfig] = useState({ url: 'https://auth.lab.taipei', realm: 'porscheworld', admin_username: 'admin', admin_password: '', }) const [testing, setTesting] = useState(false) const [testResult, setTestResult] = useState(null) const [setupPending, setSetupPending] = useState(false) const [loading, setLoading] = useState(true) const [alreadyConfigured, setAlreadyConfigured] = useState(false) // 載入已儲存的配置 useEffect(() => { loadSavedConfig() }, []) const loadSavedConfig = async () => { try { setLoading(true) const response = await fetch('http://10.1.0.245:10181/api/v1/installation/get-config/keycloak') if (!response.ok) { throw new Error(`HTTP ${response.status}`) } const data = await response.json() if (data.configured && data.config) { setConfig({ url: data.config.url || 'https://auth.lab.taipei', realm: data.config.realm || 'porscheworld', admin_username: data.config.admin_username || 'admin', admin_password: data.config.admin_password === '****' ? '' : (data.config.admin_password || ''), }) setAlreadyConfigured(true) } } catch (error) { console.error('[Keycloak] Failed to load saved config:', error) } finally { setLoading(false) } } const handleTest = async () => { try { setTesting(true) setTestResult(null) const response = await fetch('http://10.1.0.245:10181/api/v1/installation/test-keycloak', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(config), }) const data = await response.json() if (!response.ok) { setTestResult({ success: false, message: data.detail || `HTTP ${response.status}`, }) return } setTestResult(data) if (data.success) { setSetupPending(true) } } catch (error) { setTestResult({ success: false, message: error instanceof Error ? error.message : '連接失敗', }) } finally { setTesting(false) } } const handleSetup = async () => { try { const response = await fetch('http://10.1.0.245:10181/api/v1/installation/setup-keycloak', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(config), }) const data = await response.json() if (!response.ok) { alert(`設定失敗: ${data.detail}`) return } alert('Keycloak 設定成功!') router.push('/installation') } catch (error) { alert(`設定失敗: ${error instanceof Error ? error.message : '未知錯誤'}`) } } if (loading) { return (

載入已儲存的配置...

) } return (
{/* Progress Bar */}
進度 3 / 7
{/* Main Card */}
🔐

Phase 3: Keycloak SSO 設定

設定統一身份認證服務

{alreadyConfigured && (

已載入先前儲存的配置 - 您可以查看或修改下方設定

)}

說明:Keycloak 是開源的 SSO 解決方案,用於統一管理使用者身份認證。HR Portal 將透過 Keycloak 進行登入驗證。

{/* Form */}
setConfig({ ...config, url: e.target.value })} className="w-full px-4 py-2 bg-gray-700 border border-gray-600 rounded-lg text-gray-100 placeholder-gray-400 focus:ring-2 focus:ring-green-500 focus:border-transparent" placeholder="例如: https://auth.lab.taipei" />
setConfig({ ...config, realm: e.target.value })} className="w-full px-4 py-2 bg-gray-700 border border-gray-600 rounded-lg text-gray-100 placeholder-gray-400 focus:ring-2 focus:ring-green-500 focus:border-transparent" placeholder="porscheworld" />
setConfig({ ...config, admin_username: e.target.value })} className="w-full px-4 py-2 bg-gray-700 border border-gray-600 rounded-lg text-gray-100 placeholder-gray-400 focus:ring-2 focus:ring-green-500 focus:border-transparent" placeholder="admin" />
setConfig({ ...config, admin_password: e.target.value })} className="w-full px-4 py-2 bg-gray-700 border border-gray-600 rounded-lg text-gray-100 placeholder-gray-400 focus:ring-2 focus:ring-green-500 focus:border-transparent" placeholder="管理員密碼" />
{/* Test Result */} {testResult && (
{testResult.success ? '✅' : '❌'}

{testResult.success ? '連接成功' : '連接失敗'}

{testResult.message}

{testResult.success && testResult.keycloak_version && (

Keycloak 版本: {testResult.keycloak_version}

{testResult.realm_info &&

Realm 資訊: {testResult.realm_info}

}
)}
)} {/* Action Buttons */}
) }