Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions apps/client/src/pages/login-callback/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as LoginCallbackPage } from './ui/login-callback-page';
30 changes: 25 additions & 5 deletions apps/client/src/shared/router/auth-guard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,39 @@ import { Navigate, useLocation } from 'react-router';
import { getAccessToken } from '../storage/token-storage';
import { PATH } from './path';

type AuthGuardProps = {
type GuardProps = {
children: ReactNode;
};

const AuthGuard = ({ children }: AuthGuardProps) => {
const location = useLocation();
/**
* @description 인증된 사용자만 접근 가능한 페이지를 보호하는 가드
*/
export const PrivateRouteGuard = ({ children }: GuardProps) => {
const accessToken = getAccessToken();

if (!accessToken) {
return <Navigate to={PATH.LANDING} state={{ from: location }} replace />;
return <Navigate to={PATH.LANDING} replace />;
}

return <>{children}</>;
};

export default AuthGuard;
/**
* @description 인증된 사용자는 접근할 필요 없는 페이지를 처리하는 가드
*/
export const PublicRouteGuard = ({ children }: GuardProps) => {
const accessToken = getAccessToken();
const { pathname } = useLocation();

const publicOnlyPaths: string[] = [
PATH.LANDING,
PATH.LOGIN,
PATH.LOGIN_CALLBACK,
];

if (accessToken && publicOnlyPaths.includes(pathname)) {
Comment on lines +29 to +37
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const GuardedPrivateLayout = () => ( 
  <PrivateRouteGuard> 
    <PrivateLayout />
  </PrivateRouteGuard>
);

PublicRouteGuard를 PublicLayout 전체에 감싸면
PublicLayout 아래에 있는 모든 라우트가 public 영역이 되고 있기 때문에

현재 pathname이 publicOnlyPaths에 해당하나를 검사할 이유가 없을 것 같아요 !!

return <Navigate to={PATH.ALL_MEMO} replace />;
}

return <>{children}</>;
};
31 changes: 17 additions & 14 deletions apps/client/src/shared/router/router.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,29 +5,32 @@ import { createBrowserRouter } from 'react-router';

import { NotFoundPage } from '@pages/not-found';

import AuthGuard from './auth-guard';
import { privateRoutes } from './routes/private-route';
import { publicRoutes } from './routes/public-route';
import { PrivateRouteGuard, PublicRouteGuard } from './auth-guard';
import { routes } from './routes';

const PrivateLayoutWithGuard = () => {
return (
<AuthGuard>
<PrivateLayout />
</AuthGuard>
);
};
const GuardedPublicLayout = () => (
<PublicRouteGuard>
<PublicLayout />
</PublicRouteGuard>
);

const GuardedPrivateLayout = () => (
<PrivateRouteGuard>
<PrivateLayout />
</PrivateRouteGuard>
);

export const router = createBrowserRouter([
{
Component: GlobalLayout,
children: [
{
Component: PublicLayout,
children: publicRoutes,
Component: GuardedPublicLayout,
children: routes.filter((r) => !r.auth),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이런식으로 filter 함수를 사용하면 가독성이 떨어질 것 같아요 ! routes 파일을 다시 분리하게 된다면 해결될 문제 같아요 !

},
{
Component: PrivateLayoutWithGuard,
children: privateRoutes,
Component: GuardedPrivateLayout,
children: routes.filter((r) => r.auth),
},
{
path: '*',
Expand Down
54 changes: 54 additions & 0 deletions apps/client/src/shared/router/routes/index.ts
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저는 publicRoutes, privateRoutes로 라우트를 분리하는 방식이 유지보수성과 가독성 측면에서 더 낫다고 생각해요 !!

인증 필요/불필요라는 기준이 명확한 도메인 규칙이기 때문에 오히려 지금처럼 라우트를 한 배열에 섞어두면 규모가 커질수록 분류 비용과 실수 가능성이 크다고 생각합니다 !

특히 새로운 페이지 추가 시에 이 페이지가 인증이 필요한가?를 판단하고 그 결과에 따라 private/public 중 한 곳에만 넣으면 되기 때문에 변경 범위가 작고 리뷰 포인트도 명확해진다고 생각하는데 지연님의 생각은 어떨까요 ?

또한 SSoT 위배 라고 말씀해주셨는데 분리 자체는 중복 정의가 아니라 책임 분리에 가깝다고 생각해요 !
SSoT가 실제로 깨지는 케이스는 이 페이지가 private인지 여부와 같은 동일한 규칙이 routes 파일/guard/메뉴 매핑 등 여러 곳에서 중복으로 관리되어 불일치가 생길 때인데 현재 구조는 접근 정책을 privateRoutes/publicRoutes라는 한 기준으로 모아두는 형태라 오히려 정책을 추적하기 쉽다고 생각합니다 !!

Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { RouteObject } from 'react-router';

import { LandingPage } from '@pages/landing';
import { LoginCallbackPage } from '@pages/login-callback';

import {
AiResultsPage,
AllMemoPage,
LabelPage,
LoginPage,
NewMemoPage,
} from '../lazy';
import { PATH } from '../path';

type AuthRouteObject = RouteObject & {
auth?: boolean;
};

export const routes: AuthRouteObject[] = [
// Private Routes
{
path: PATH.NEW_MEMO,
Component: NewMemoPage,
auth: true,
},
{
path: PATH.ALL_MEMO,
Component: AllMemoPage,
auth: true,
},
{
path: PATH.AI_RESULTS,
Component: AiResultsPage,
auth: true,
},
{
path: PATH.LABEL,
Component: LabelPage,
auth: true,
},
// Public Routes
{
path: PATH.LOGIN,
Component: LoginPage,
},
{
path: PATH.LOGIN_CALLBACK,
Component: LoginCallbackPage,
},
{
path: PATH.LANDING,
Component: LandingPage,
},
];
23 changes: 0 additions & 23 deletions apps/client/src/shared/router/routes/private-route.ts

This file was deleted.

22 changes: 0 additions & 22 deletions apps/client/src/shared/router/routes/public-route.ts

This file was deleted.

Loading