diff --git a/adminfront/src/app/routes.tsx b/adminfront/src/app/routes.tsx index 44a2c5b0..913491e2 100644 --- a/adminfront/src/app/routes.tsx +++ b/adminfront/src/app/routes.tsx @@ -7,6 +7,7 @@ import AuthPage from "../features/auth/AuthPage"; import DashboardPage from "../features/dashboard/DashboardPage"; import GlobalOverviewPage from "../features/overview/GlobalOverviewPage"; import LoginPage from "../features/auth/LoginPage"; +import AuthCallbackPage from "../features/auth/AuthCallbackPage"; import TenantGroupCreatePage from "../features/tenant-groups/routes/TenantGroupCreatePage"; import TenantGroupDetailPage from "../features/tenant-groups/routes/TenantGroupDetailPage"; import TenantGroupListPage from "../features/tenant-groups/routes/TenantGroupListPage"; @@ -29,6 +30,10 @@ export const router = createBrowserRouter( path: "/login", element: , }, + { + path: "/auth/callback", + element: , + }, { path: "/", element: , diff --git a/adminfront/src/features/auth/AuthCallbackPage.tsx b/adminfront/src/features/auth/AuthCallbackPage.tsx new file mode 100644 index 00000000..fb98fa68 --- /dev/null +++ b/adminfront/src/features/auth/AuthCallbackPage.tsx @@ -0,0 +1,34 @@ +import { useEffect } from "react"; +import { useNavigate, useSearchParams } from "react-router-dom"; +import { ShieldHalf } from "lucide-react"; + +function AuthCallbackPage() { + const navigate = useNavigate(); + const [searchParams] = useSearchParams(); + + useEffect(() => { + const token = searchParams.get("token"); + if (token) { + window.localStorage.setItem("admin_session", token); + // Redirect to home after a short delay or immediately + navigate("/", { replace: true }); + } else { + console.error("No token found in callback URL"); + navigate("/login", { replace: true }); + } + }, [navigate, searchParams]); + + return ( +
+
+
+ +
+
인증 완료 중...
+

세션을 동기화하고 있습니다.

+
+
+ ); +} + +export default AuthCallbackPage; diff --git a/adminfront/src/features/auth/LoginPage.tsx b/adminfront/src/features/auth/LoginPage.tsx index 3e553d80..1897dc57 100644 --- a/adminfront/src/features/auth/LoginPage.tsx +++ b/adminfront/src/features/auth/LoginPage.tsx @@ -29,10 +29,16 @@ function LoginPage() { return () => window.removeEventListener("message", handleMessage); }, [navigate]); - const handleSSOLogin = () => { + const handleSSOLogin = (mode: "popup" | "redirect" = "popup") => { const userfrontUrl = import.meta.env.USERFRONT_URL || "https://sso.hmac.kr"; - const loginUrl = `${userfrontUrl}/ssologin?source=adminfront`; + const callbackUrl = `${window.location.origin}/auth/callback`; + const loginUrl = `${userfrontUrl}/ssologin?source=adminfront&redirect_uri=${encodeURIComponent(callbackUrl)}`; + if (mode === "redirect") { + window.location.href = loginUrl; + return; + } + const width = 500; const height = 700; const left = window.screen.width / 2 - width / 2; @@ -54,7 +60,8 @@ function LoginPage() { } }, 1000); } else { - alert("팝업 차단이 설정되어 있습니다. 팝업 허용 후 다시 시도해 주세요."); + // If popup blocked, fallback to redirect + window.location.href = loginUrl; } }; @@ -83,9 +90,9 @@ function LoginPage() { Baron 통합 인증(SSO)을 통해 관리자 페이지에 접속합니다. - + + +

관리자 전역 세션은 보안을 위해 15분간 유지됩니다.
diff --git a/userfront/lib/core/services/web_auth_integration_web.dart b/userfront/lib/core/services/web_auth_integration_web.dart index 7e227de3..ab5c0a3d 100644 --- a/userfront/lib/core/services/web_auth_integration_web.dart +++ b/userfront/lib/core/services/web_auth_integration_web.dart @@ -5,6 +5,21 @@ import 'dart:html' as html; import 'package:flutter/foundation.dart'; void implSendLoginSuccess(String token) { + final uri = Uri.parse(html.window.location.href); + final redirectUri = uri.queryParameters['redirect_uri']; + + if (redirectUri != null && redirectUri.isNotEmpty) { + // Redirection flow + final target = Uri.parse(redirectUri); + final query = Map.from(target.queryParameters); + query['token'] = token; + final finalUri = target.replace(queryParameters: query); + + debugPrint('Redirecting to: ${finalUri.toString()}'); + html.window.location.href = finalUri.toString(); + return; + } + final message = {'type': 'LOGIN_SUCCESS', 'token': token}; if (html.window.opener != null) { diff --git a/userfront/lib/main.dart b/userfront/lib/main.dart index 5c94c1b1..3138ef12 100644 --- a/userfront/lib/main.dart +++ b/userfront/lib/main.dart @@ -98,6 +98,13 @@ final _router = GoRouter( return LoginScreen(key: state.pageKey, loginChallenge: loginChallenge); }, ), + GoRoute( + path: '/ssologin', + builder: (context, state) { + _routerLogger.info("Navigating to /ssologin"); + return LoginScreen(key: state.pageKey); + }, + ), GoRoute( path: '/login', builder: (context, state) {