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) {