Skip to content

Commit 466cdf2

Browse files
committed
fix: 로그인 redirect 파라미터 의존 로직 제거 (#444)
1 parent 79a2e12 commit 466cdf2

7 files changed

Lines changed: 11 additions & 86 deletions

File tree

apps/web/src/apis/Auth/postAppleAuth.ts

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,16 @@
11
import { useMutation } from "@tanstack/react-query";
22

33
import type { AxiosError } from "axios";
4-
import { useRouter, useSearchParams } from "next/navigation";
4+
import { useRouter } from "next/navigation";
55
import useAuthStore from "@/lib/zustand/useAuthStore";
66
import { toast } from "@/lib/zustand/useToastStore";
7-
import { validateSafeRedirect } from "@/utils/authUtils";
87
import { type AppleAuthRequest, type AppleAuthResponse, authApi } from "./api";
98

109
/**
1110
* @description 애플 로그인을 위한 useMutation 커스텀 훅
1211
*/
1312
const usePostAppleAuth = () => {
1413
const router = useRouter();
15-
const searchParams = useSearchParams();
1614

1715
return useMutation<AppleAuthResponse, AxiosError, AppleAuthRequest>({
1816
mutationFn: (data) => authApi.postAppleAuth(data),
@@ -22,14 +20,10 @@ const usePostAppleAuth = () => {
2220
// refreshToken은 서버에서 HTTP-only 쿠키로 자동 설정됨
2321
useAuthStore.getState().setAccessToken(data.accessToken);
2422

25-
// 안전한 리다이렉트 처리 - 오픈 리다이렉트 방지
26-
const redirectParam = searchParams.get("redirect");
27-
const safeRedirect = validateSafeRedirect(redirectParam);
28-
2923
toast.success("로그인에 성공했습니다.");
3024

3125
setTimeout(() => {
32-
router.push(safeRedirect);
26+
router.push("/");
3327
}, 100);
3428
} else {
3529
// 새로운 회원일 시 - 회원가입 페이지로 이동

apps/web/src/apis/Auth/postEmailLogin.ts

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,16 @@
11
import { useMutation } from "@tanstack/react-query";
22

33
import type { AxiosError } from "axios";
4-
import { useRouter, useSearchParams } from "next/navigation";
4+
import { useRouter } from "next/navigation";
55
import useAuthStore from "@/lib/zustand/useAuthStore";
66
import { toast } from "@/lib/zustand/useToastStore";
7-
import { validateSafeRedirect } from "@/utils/authUtils";
87
import { authApi, type EmailLoginRequest, type EmailLoginResponse } from "./api";
98

109
/**
1110
* @description 이메일 로그인을 위한 useMutation 커스텀 훅
1211
*/
1312
const usePostEmailAuth = () => {
1413
const { setAccessToken } = useAuthStore();
15-
const searchParams = useSearchParams();
1614
const router = useRouter();
1715

1816
return useMutation<EmailLoginResponse, AxiosError, EmailLoginRequest>({
@@ -24,16 +22,12 @@ const usePostEmailAuth = () => {
2422
// refreshToken은 서버에서 HTTP-only 쿠키로 자동 설정됨
2523
setAccessToken(accessToken);
2624

27-
// 안전한 리다이렉트 처리 - 오픈 리다이렉트 방지
28-
const redirectParam = searchParams.get("redirect");
29-
const safeRedirect = validateSafeRedirect(redirectParam);
30-
3125
toast.success("로그인에 성공했습니다.");
3226

3327
// Zustand persist middleware가 localStorage에 저장할 시간을 보장
3428
// 토큰 저장 후 리다이렉트하여 타이밍 이슈 방지
3529
setTimeout(() => {
36-
router.push(safeRedirect);
30+
router.push("/");
3731
}, 100);
3832
},
3933
});

apps/web/src/apis/Auth/postKakaoAuth.ts

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
import { useMutation } from "@tanstack/react-query";
22

33
import type { AxiosError } from "axios";
4-
import { useRouter, useSearchParams } from "next/navigation";
4+
import { useRouter } from "next/navigation";
55
import useAuthStore from "@/lib/zustand/useAuthStore";
66
import { toast } from "@/lib/zustand/useToastStore";
7-
import { validateSafeRedirect } from "@/utils/authUtils";
87
import { authApi, type KakaoAuthRequest, type KakaoAuthResponse } from "./api";
98

109
/**
@@ -13,7 +12,6 @@ import { authApi, type KakaoAuthRequest, type KakaoAuthResponse } from "./api";
1312
const usePostKakaoAuth = () => {
1413
const { setAccessToken } = useAuthStore();
1514
const router = useRouter();
16-
const searchParams = useSearchParams();
1715

1816
return useMutation<KakaoAuthResponse, AxiosError, KakaoAuthRequest>({
1917
mutationFn: (data) => authApi.postKakaoAuth(data),
@@ -23,14 +21,10 @@ const usePostKakaoAuth = () => {
2321
// refreshToken은 서버에서 HTTP-only 쿠키로 자동 설정됨
2422
setAccessToken(data.accessToken);
2523

26-
// 안전한 리다이렉트 처리 - 오픈 리다이렉트 방지
27-
const redirectParam = searchParams.get("redirect");
28-
const safeRedirect = validateSafeRedirect(redirectParam);
29-
3024
toast.success("로그인에 성공했습니다.");
3125

3226
setTimeout(() => {
33-
router.push(safeRedirect);
27+
router.push("/");
3428
}, 100);
3529
} else {
3630
// 새로운 회원일 시 - 회원가입 페이지로 이동

apps/web/src/app/login/LoginContent.tsx

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,10 @@
22

33
import { zodResolver } from "@hookform/resolvers/zod";
44
import Link from "next/link";
5-
import { useRouter, useSearchParams } from "next/navigation";
6-
import { useEffect } from "react";
5+
import { useRouter } from "next/navigation";
76
import { useForm } from "react-hook-form";
87
import { z } from "zod";
98
import { usePostEmailAuth } from "@/apis/Auth";
10-
import { toast } from "@/lib/zustand/useToastStore";
119
import { IconSolidConnectionFullBlackLogo } from "@/public/svgs";
1210
import { IconAppleLogo, IconEmailIcon, IconKakaoLogo } from "@/public/svgs/auth";
1311
import { appleLogin, kakaoLogin } from "@/utils/authUtils";
@@ -23,7 +21,6 @@ type LoginFormData = z.infer<typeof loginSchema>;
2321

2422
const LoginContent = () => {
2523
const router = useRouter();
26-
const searchParams = useSearchParams();
2724

2825
const { mutate: postEmailAuth, isPending } = usePostEmailAuth();
2926
const { showPasswordField, handleEmailChange } = useInputHandler();
@@ -40,14 +37,6 @@ const LoginContent = () => {
4037
},
4138
});
4239

43-
// redirect 파라미터가 있으면 로그인 필요 토스트 표시
44-
useEffect(() => {
45-
const redirect = searchParams.get("redirect");
46-
if (redirect) {
47-
toast.info("로그인이 필요합니다.");
48-
}
49-
}, [searchParams]);
50-
5140
const onSubmit = async (data: LoginFormData) => {
5241
postEmailAuth(data, {});
5342
};

apps/web/src/app/mentor/_ui/MentorClient/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ const MentorClient = () => {
4242
} catch {
4343
// 재발급 실패 시 로그인 페이지로 리다이렉트
4444
setRefreshStatus("failed");
45-
router.push("/login?redirect=/mentor");
45+
router.push("/login");
4646
} finally {
4747
setIsRefreshing(false);
4848
}

apps/web/src/middleware.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,6 @@ export function middleware(request: NextRequest) {
3232

3333
if (needLogin && !refreshToken) {
3434
url.pathname = "/login";
35-
// 전체 URL(pathname + search) 보존하여 리다이렉트 파라미터에 설정
36-
const redirectUrl = request.nextUrl.pathname + request.nextUrl.search;
37-
url.searchParams.set("redirect", redirectUrl);
3835
return NextResponse.redirect(url);
3936
}
4037

apps/web/src/utils/authUtils.ts

Lines changed: 3 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,6 @@
11
import { toast } from "@/lib/zustand/useToastStore";
22
import type { appleOAuth2CodeResponse } from "@/types/auth";
33

4-
// 오픈 리다이렉트 공격 방지를 위한 redirect 파라미터 검증
5-
// 단일 "/"로 시작하고 "//"나 "://"를 포함하지 않는 내부 경로만 허용
6-
export const validateSafeRedirect = (redirectParam: string | null): string => {
7-
if (!redirectParam || typeof redirectParam !== "string") {
8-
return "/";
9-
}
10-
11-
if (redirectParam.startsWith("/") && !redirectParam.startsWith("//") && !redirectParam.includes("://")) {
12-
return redirectParam;
13-
}
14-
15-
return "/";
16-
};
17-
184
export const authProviderName = (provider: "KAKAO" | "APPLE" | "EMAIL"): string => {
195
if (provider === "KAKAO") {
206
return "카카오";
@@ -29,20 +15,8 @@ export const authProviderName = (provider: "KAKAO" | "APPLE" | "EMAIL"): string
2915

3016
export const kakaoLogin = () => {
3117
if (window.Kakao?.Auth) {
32-
// 현재 URL에서 redirect 파라미터 추출 및 검증
33-
const urlParams = new URLSearchParams(window.location.search);
34-
const redirectParam = urlParams.get("redirect");
35-
const safeRedirect = validateSafeRedirect(redirectParam);
36-
37-
// 검증된 redirect 파라미터를 callback URL에 전달
38-
let redirectUri = `${process.env.NEXT_PUBLIC_WEB_URL}/login/kakao/callback`;
39-
// 기본값 "/"가 아닌 경우에만 redirect 파라미터 추가 (기본값이면 생략 가능)
40-
if (safeRedirect !== "/") {
41-
redirectUri += `?redirect=${encodeURIComponent(safeRedirect)}`;
42-
}
43-
4418
window.Kakao.Auth.authorize({
45-
redirectUri,
19+
redirectUri: `${process.env.NEXT_PUBLIC_WEB_URL}/login/kakao/callback`,
4620
});
4721
} else {
4822
toast.error("Kakao SDK를 불러오는 중입니다. 잠시 후 다시 시도해주세요.");
@@ -55,34 +29,17 @@ export const appleLogin = async () => {
5529
return;
5630
}
5731

58-
// 현재 URL에서 redirect 파라미터 추출 및 검증
59-
const urlParams = new URLSearchParams(window.location.search);
60-
const redirectParam = urlParams.get("redirect");
61-
const safeRedirect = validateSafeRedirect(redirectParam);
62-
63-
// 검증된 redirect 파라미터를 callback URL에 전달
64-
let redirectURI = `${process.env.NEXT_PUBLIC_WEB_URL}/login/apple/callback`;
65-
// 기본값 "/"가 아닌 경우에만 redirect 파라미터 추가 (기본값이면 생략 가능)
66-
if (safeRedirect !== "/") {
67-
redirectURI += `?redirect=${encodeURIComponent(safeRedirect)}`;
68-
}
69-
7032
window.AppleID.auth.init({
7133
clientId: process.env.NEXT_PUBLIC_APPLE_CLIENT_ID,
7234
scope: process.env.NEXT_PUBLIC_APPLE_SCOPE,
73-
redirectURI,
35+
redirectURI: `${process.env.NEXT_PUBLIC_WEB_URL}/login/apple/callback`,
7436
usePopup: true,
7537
});
7638

7739
try {
7840
const res = (await window.AppleID.auth.signIn()) as appleOAuth2CodeResponse;
7941
if (res.authorization) {
80-
// 검증된 redirect 파라미터를 callback URL에 전달
81-
let callbackUrl = `/login/apple/callback?code=${encodeURIComponent(res.authorization.code)}`;
82-
if (safeRedirect !== "/") {
83-
callbackUrl += `&redirect=${encodeURIComponent(safeRedirect)}`;
84-
}
85-
window.location.href = callbackUrl;
42+
window.location.href = `/login/apple/callback?code=${encodeURIComponent(res.authorization.code)}`;
8643
}
8744
} catch (error) {
8845
// Log error for developers

0 commit comments

Comments
 (0)