-
Notifications
You must be signed in to change notification settings - Fork 2
Fix: 기존 authGuard 수정 및 리다이렉트 모달 추가, 프록시 경로 추가 #100
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 5 commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
4477b66
feat: 로그인 리다이렉트 모달 생성
youdaeng2 92268ff
fix: 레거시 authGuard 고차함수 패턴으로 리팩토링
youdaeng2 45342a2
fix: 변경된 authGuard에 맞춰 사용처 수정
youdaeng2 21ef7d7
fix: 게시글 좋아요 버튼 인증 가드 중복 호출 제거
youdaeng2 c28d8bc
fix: 프록시 대상 경로에 자유/투표 게시판 추가, SSR에서는 /api 리라이트를 건너뛰도록 isBrowser 분기 추가…
youdaeng2 49b5426
Merge branch 'dev' into fix/SOS-48-freeboard-auth-guard
DreamPaste File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,88 @@ | ||
| 'use client'; | ||
|
|
||
| import { useRouter, usePathname } from 'next/navigation'; | ||
| import Modal from './Modal'; | ||
|
|
||
| interface LoginRedirectOverlayProps { | ||
| // useOverlay.open()에서 내려주는 close 함수 | ||
| // - result: 호출 쪽에 resolve로 넘겨줄 값 | ||
| // - options: fadeOut 여부, 애니메이션 duration(ms) | ||
| close: ( | ||
| result: boolean, | ||
| options?: { | ||
| fadeOut?: boolean; | ||
| duration?: number; | ||
| }, | ||
| ) => void; | ||
| } | ||
|
|
||
| /** | ||
| * 비로그인 상태에서 행동 시 띄우는 "로그인 리다이렉트" 오버레이 | ||
| * | ||
| * - 전체 화면을 fixed로 덮고 가운데에 Modal을 띄운다 | ||
| * - 배경을 클릭했을 때는 클릭이 통과되도록 pointer-events 설정 | ||
| * - 버튼 클릭 시에만 실제 클릭 이벤트가 동작하도록 분리 | ||
| */ | ||
| export function LoginRedirectOverlay({ | ||
| close, | ||
| }: LoginRedirectOverlayProps) { | ||
| const router = useRouter(); | ||
| const pathname = usePathname(); | ||
|
|
||
| // 취소: 로그인 페이지로 이동하지 않고 모달만 닫기 | ||
| const handleCancel = () => { | ||
| close(false, { fadeOut: true, duration: 300 }); | ||
| }; | ||
|
|
||
| // 확인: 로그인 페이지로 이동 + 모달 닫기 | ||
| // - 현재 경로(pathname)를 returnTo로 넘겨서 로그인 후 되돌아올 수 있게 함 | ||
| const handleConfirm = () => { | ||
| const returnTo = encodeURIComponent(pathname || '/'); | ||
| router.push(`/login?returnTo=${returnTo}`); | ||
| close(true, { fadeOut: true, duration: 300 }); | ||
| }; | ||
|
|
||
| return ( | ||
| // 전체 화면을 덮는 오버레이 레이어 | ||
| <div className="fixed inset-0 flex items-center justify-center pointer-events-none"> | ||
| {/* 실제 인터랙션이 일어나는 영역만 pointer-events 활성화 */} | ||
| <Modal | ||
| isOpen | ||
| onClose={handleCancel} | ||
| className="relative pointer-events-auto" | ||
| > | ||
| {/* 모달 내부 레이아웃: 수직 정렬 + 여백 */} | ||
| <div className="flex flex-col gap-4 w-full h-full"> | ||
| <h2 className="text-lg font-semibold text-center"> | ||
| 로그인이 필요합니다 | ||
| </h2> | ||
|
|
||
| <p className="text-sm text-center text-gray-500"> | ||
| 로그인이 필요한 기능이에요. | ||
| <br /> | ||
| 로그인하러 이동할까요? | ||
| </p> | ||
|
|
||
| {/* 버튼 영역: 가운데 정렬, 버튼 간 간격 */} | ||
| <div className="mt-4 flex justify-center gap-2"> | ||
| <button | ||
| type="button" | ||
| className="px-3 py-1.5 text-sm rounded-lg border border-gray-300" | ||
| onClick={handleCancel} | ||
| > | ||
| 취소 | ||
| </button> | ||
|
|
||
| <button | ||
| type="button" | ||
| className="px-3 py-1.5 text-sm rounded-lg bg-primary text-white" | ||
| onClick={handleConfirm} | ||
| > | ||
| 로그인하러 가기 | ||
| </button> | ||
| </div> | ||
| </div> | ||
| </Modal> | ||
| </div> | ||
| ); | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,8 +5,10 @@ import { | |
| } from '@/generated/api/endpoints/users/users'; | ||
| import { ApiError } from '@/lib/api-error'; | ||
| import type { UserResponse } from '@/generated/api/models'; | ||
| import { useToast } from './ui/useToast'; | ||
| import { useLogout } from './useLogout'; | ||
| import { useOverlay } from './ui/useOverlay'; | ||
| import React from 'react'; | ||
| import { LoginRedirectOverlay } from '@/components/LoginRedirectOverlay'; | ||
|
|
||
| /** | ||
| * 현재 로그인한 사용자 정보를 조회하는 Hook | ||
|
|
@@ -83,60 +85,61 @@ export function useAuthRestore() { | |
| } | ||
|
|
||
| /** | ||
| * 인증 가드 Hook (기존 코드 호환성 유지) | ||
| * | ||
| * ## 반환값 | ||
| * - `authed`: 인증 여부 (boolean) | ||
| * - `guard(fn)`: 인증된 경우에만 fn 실행, 아니면 토스트 표시 | ||
| * - `ensureAuthed()`: 인증 여부 체크, false면 토스트 표시 | ||
| * | ||
| * ## 레거시 호환 | ||
| * 기존 코드에서 사용하던 guard/ensureAuthed 패턴을 유지합니다. | ||
| * 내부적으로는 새로운 useAuth()를 사용하여 SSR 최적화를 활용합니다. | ||
| * 행동 단위 인증 가드 Hook (HOF 패턴) | ||
| * | ||
| * - 인증된 상태: 넘겨준 액션(fn)을 그대로 실행 | ||
| * - 비인증 상태: 로그인 리다이렉트 오버레이를 띄우고, 액션은 실행하지 않음 | ||
| */ | ||
| export function useAuthGuard( | ||
| options: { onUnauthed?: () => void } = {}, | ||
| ) { | ||
| export function useAuthGuard() { | ||
| // 현재 로그인 여부 | ||
| const { isAuth } = useAuth(); | ||
| const toast = useToast(); | ||
|
|
||
| // 비로그인 기본 처리: 토스트 표시 (기존 동작 유지) | ||
| // 옵션으로 커스텀 동작 지정 가능 (예: 리다이렉트) | ||
| const onUnauthed = | ||
| options.onUnauthed ?? | ||
| (() => toast('로그인이 필요합니다.', 'error')); | ||
| // 전역 오버레이 제어 훅 | ||
| const { open } = useOverlay(); | ||
|
|
||
| /** | ||
| * 인증된 경우에만 함수 실행 | ||
| * @param fn - 실행할 함수 | ||
| * 내부 헬퍼: "지금 로그인 되어 있는지" 확인하는 함수 | ||
| * | ||
| * - 로그인 X: | ||
| * - LoginRedirectOverlay 오버레이를 띄움 | ||
| * - false 반환 | ||
| * - 로그인 O: | ||
| * - true 반환 | ||
| */ | ||
| const guard = (fn: () => void | Promise<void>) => { | ||
| const ensureAuthed = async () => { | ||
| if (!isAuth) { | ||
| onUnauthed(); | ||
| return; | ||
| } | ||
| return fn(); | ||
| }; | ||
|
|
||
| /** | ||
| * 인증 여부 확인 (조기 리턴 패턴에 사용) | ||
| * @returns 인증 여부 | ||
| */ | ||
| const ensureAuthed = () => { | ||
| if (!isAuth) { | ||
| onUnauthed(); | ||
| // 오버레이 스택에 로그인 리다이렉트 모달 추가 | ||
| await open<boolean>( | ||
| // renderer: close 함수를 받아서 오버레이 컴포넌트를 렌더링 | ||
| ({ close }) => | ||
| React.createElement(LoginRedirectOverlay, { close }), | ||
| { | ||
| blockScroll: true, | ||
| closeOnBackdrop: true, | ||
| }, | ||
| ); | ||
| return false; | ||
| } | ||
| return true; | ||
| }; | ||
|
|
||
| /** | ||
| * 고차함수(HOF) 패턴 | ||
| * | ||
| * - 인자: fn: 실제로 실행하고 싶은 액션(함수) | ||
| * - 반환: 로그인 체크가 래핑된 새 함수 | ||
| **/ | ||
| const requireAuth = | ||
| // Args: 원래 함수가 받을 인자 타입들 | ||
| <Args extends unknown[]>( | ||
| fn: (...args: Args) => void | Promise<void>, | ||
| ) => | ||
| async (...args: Args) => { | ||
| if (!(await ensureAuthed())) return; | ||
| return fn(...args); | ||
| }; | ||
|
|
||
|
Comment on lines
+125
to
+140
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. HOF 패턴이네요 고생하셨어요 |
||
| return { | ||
| /** 인증 여부 */ | ||
| authed: isAuth, | ||
| /** 인증된 경우에만 fn 실행 */ | ||
| guard, | ||
| /** 인증 여부 확인 후 false면 onUnauthed 실행 */ | ||
| ensureAuthed, | ||
| requireAuth, | ||
| }; | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
위처럼 한번에 해도 좋을거같아요!