5812925929
Build & Deploy to K8s / build-and-deploy (push) Failing after 3m6s
- 백엔드 TenantController: GET /api/tenant/check?subdomain=xxx (메타 DB 강제 라우팅 + CompanyResolver 로 존재 여부 반환) - frontend/lib/tenant/subdomain.ts: 호스트 파싱 + 예약어(solution/www/admin 등) 제외 - TenantGuard 클라이언트 컴포넌트: layout.tsx 에서 wrap, sessionStorage 로 같은 서브도메인 재체크 방지 - /tenant-not-found 페이지: v5 solid+glow 스타일 등록되지 않은 서브도메인 접속 시 즉시 /tenant-not-found 로 리다이렉트.
47 lines
1.5 KiB
TypeScript
47 lines
1.5 KiB
TypeScript
"use client";
|
|
|
|
import { useEffect } from "react";
|
|
import { usePathname, useRouter } from "next/navigation";
|
|
import { apiClient } from "@/lib/api/client";
|
|
import { extractTenantSubdomain } from "@/lib/tenant/subdomain";
|
|
|
|
const CHECK_CACHE_KEY = "tenant-check-ok";
|
|
|
|
/**
|
|
* 테넌트 서브도메인 접근 차단 Guard.
|
|
* - 메인 사이트(solution.invyone.com 등 예약어) 는 통과
|
|
* - *.invyone.com 테넌트 서브도메인은 백엔드 /api/tenant/check 로 존재 검증
|
|
* - 미등록 회사면 /tenant-not-found 로 리다이렉트
|
|
*
|
|
* 같은 세션 내 재체크를 피하려고 sessionStorage 에 1회 캐시.
|
|
*/
|
|
export function TenantGuard({ children }: { children: React.ReactNode }) {
|
|
const router = useRouter();
|
|
const pathname = usePathname();
|
|
|
|
useEffect(() => {
|
|
if (typeof window === "undefined") return;
|
|
if (pathname === "/tenant-not-found") return;
|
|
|
|
const sub = extractTenantSubdomain(window.location.hostname);
|
|
if (!sub) return;
|
|
|
|
if (sessionStorage.getItem(CHECK_CACHE_KEY) === sub) return;
|
|
|
|
apiClient
|
|
.get(`/tenant/check`, { params: { subdomain: sub } })
|
|
.then((res) => {
|
|
if (res.data?.exists) {
|
|
sessionStorage.setItem(CHECK_CACHE_KEY, sub);
|
|
} else {
|
|
router.replace("/tenant-not-found");
|
|
}
|
|
})
|
|
.catch(() => {
|
|
// API 호출 실패 시 낙관적으로 통과. 백엔드 잠시 재기동 중일 수 있음.
|
|
});
|
|
}, [pathname, router]);
|
|
|
|
return <>{children}</>;
|
|
}
|