summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/api/auth/[...nextauth]/route.ts27
-rw-r--r--app/api/test/headers/route.ts80
-rw-r--r--components/layout/Header.tsx2
-rw-r--r--components/layout/HeaderDataroom.tsx7
4 files changed, 107 insertions, 9 deletions
diff --git a/app/api/auth/[...nextauth]/route.ts b/app/api/auth/[...nextauth]/route.ts
index d6ec807f..58566cd6 100644
--- a/app/api/auth/[...nextauth]/route.ts
+++ b/app/api/auth/[...nextauth]/route.ts
@@ -449,12 +449,35 @@ export const authOptions: NextAuthOptions = {
},
async redirect({ url, baseUrl }) {
+ // 상대 경로인 경우 baseUrl과 결합
if (url.startsWith("/")) {
return `${baseUrl}${url}`;
}
- else if (new URL(url).origin === baseUrl) {
- return url;
+
+ // 절대 URL인 경우: 허용된 도메인 목록 확인
+ try {
+ const urlObj = new URL(url);
+ const allowedDomains = [
+ "shidataroom.com",
+ "partners.sevcp.com",
+ "sevcp.com",
+ "localhost" // 개발 환경
+ ];
+
+ // 허용된 도메인이면 그대로 반환
+ if (allowedDomains.includes(urlObj.hostname)) {
+ return url;
+ }
+
+ // 기존 로직: baseUrl과 origin이 같으면 허용
+ if (urlObj.origin === baseUrl) {
+ return url;
+ }
+ } catch {
+ console.error('Invalid redirect URL:', url);
}
+
+ // 허용되지 않은 URL은 baseUrl로 리다이렉트
return baseUrl;
},
},
diff --git a/app/api/test/headers/route.ts b/app/api/test/headers/route.ts
new file mode 100644
index 00000000..70c14564
--- /dev/null
+++ b/app/api/test/headers/route.ts
@@ -0,0 +1,80 @@
+import { NextRequest, NextResponse } from 'next/server';
+import { headers } from 'next/headers';
+
+/**
+ * 리버스 프록시 헤더 전달 테스트 API
+ *
+ * 접속 방법:
+ * - https://shidataroom.com/api/test/headers
+ * - https://partners.sevcp.com/api/test/headers
+ * - https://sevcp.com/api/test/headers
+ *
+ * 각 도메인에서 헤더가 올바르게 전달되는지 확인
+ */
+export async function GET(request: NextRequest) {
+ const headersList = await headers();
+
+ // 중요한 헤더들 수집
+ const host = headersList.get('host');
+ const xForwardedProto = headersList.get('x-forwarded-proto');
+ const xForwardedHost = headersList.get('x-forwarded-host');
+ const xForwardedFor = headersList.get('x-forwarded-for');
+ const xRealIp = headersList.get('x-real-ip');
+
+ // 현재 계산된 origin
+ const proto = xForwardedProto || 'http';
+ const computedOrigin = `${proto}://${host}`;
+
+ // request.nextUrl의 origin (Next.js가 인식하는 origin)
+ const nextUrlOrigin = request.nextUrl.origin;
+
+ return NextResponse.json({
+ success: true,
+ message: '리버스 프록시 헤더 정보',
+ headers: {
+ host,
+ 'x-forwarded-proto': xForwardedProto,
+ 'x-forwarded-host': xForwardedHost,
+ 'x-forwarded-for': xForwardedFor,
+ 'x-real-ip': xRealIp,
+ },
+ computed: {
+ origin: computedOrigin,
+ nextUrlOrigin,
+ isCorrect: computedOrigin === nextUrlOrigin,
+ },
+ recommendations: {
+ dmz_nginx: {
+ required: [
+ 'proxy_set_header Host $host;',
+ 'proxy_set_header X-Forwarded-Proto $scheme;',
+ 'proxy_set_header X-Forwarded-Host $host;',
+ 'proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;',
+ 'proxy_set_header X-Real-IP $remote_addr;',
+ ]
+ },
+ ap_nginx: {
+ required: [
+ 'proxy_set_header Host $host;',
+ 'proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;',
+ 'proxy_set_header X-Forwarded-Host $http_x_forwarded_host;',
+ 'proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;',
+ 'proxy_set_header X-Real-IP $http_x_real_ip;',
+ ]
+ }
+ },
+ test: {
+ description: '각 도메인에서 이 API를 호출하여 헤더가 올바른지 확인하세요',
+ expected: {
+ 'shidataroom.com': 'computed.origin should be "https://shidataroom.com"',
+ 'partners.sevcp.com': 'computed.origin should be "https://partners.sevcp.com"',
+ 'sevcp.com': 'computed.origin should be "https://sevcp.com"',
+ }
+ }
+ }, {
+ headers: {
+ 'Content-Type': 'application/json',
+ }
+ });
+}
+
diff --git a/components/layout/Header.tsx b/components/layout/Header.tsx
index c9455fc8..55991d2c 100644
--- a/components/layout/Header.tsx
+++ b/components/layout/Header.tsx
@@ -261,7 +261,7 @@ export function Header() {
<Link href={`${basePath}/settings`}>{t('user.settings')}</Link>
</DropdownMenuItem>
<DropdownMenuSeparator />
- <DropdownMenuItem onSelect={() => signOut({ callbackUrl: `/${lng}/${domain}` })}>
+ <DropdownMenuItem onSelect={() => signOut({ callbackUrl: `${window.location.origin}${basePath}` })}>
{t('user.logout')}
</DropdownMenuItem>
</DropdownMenuContent>
diff --git a/components/layout/HeaderDataroom.tsx b/components/layout/HeaderDataroom.tsx
index 0981b24b..04d61a8d 100644
--- a/components/layout/HeaderDataroom.tsx
+++ b/components/layout/HeaderDataroom.tsx
@@ -138,12 +138,7 @@ export function HeaderDataRoom() {
<Link href={`/${lng}/evcp/settings`}>설정</Link>
</DropdownMenuItem>
<DropdownMenuSeparator />
- <DropdownMenuItem onSelect={() => {
- const logoutUrl = domain === 'partners'
- ? 'https://shidataroom.com/en/partners'
- : `/${lng}/${domain}`;
- signOut({ callbackUrl: logoutUrl });
- }}>
+ <DropdownMenuItem onSelect={() => signOut({ callbackUrl: `${window.location.origin}/${lng}/evcp` })}>
로그아웃
</DropdownMenuItem>
</DropdownMenuContent>