Skip to content

Commit

Permalink
feat: 특정 페이지 진입시 auth 여부 체크하는 로직 구현
Browse files Browse the repository at this point in the history
withAuth 함수를 정의하여 특정 페이지 진입시 auth 여부에 따라 분기 처리할 수 있도록 했다.
원하는 페이지 컴포넌트에 withAuth 함수를 씌워 export 하면 된다.한 가지 단점은 react hook을
사용하는 기능이기 때문에 해당 페이지를 client component로 선언해야 한다는 점이다.
또한, auth 관련 fetching 과정에서 loading 중인 state를 기록하기 위해 authInfo에 isLoading이란 속성을
추가했다.
  • Loading branch information
oooppq committed Sep 13, 2023
1 parent 997b542 commit 11c973c
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 9 deletions.
9 changes: 6 additions & 3 deletions components/AuthProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,13 @@ const AuthProvider = ({ children }: { children: React.ReactNode }) => {
const { refresh } = useAuth();

useEffect(() => {
// refresh 여부를 알 수 있는 코드, 당장은 필요 없으나 이후 의도치 않은 refresh가 계속 발생할 경우 사용
// const entries = performance.getEntriesByType('navigation')[0];
// const entriesNavigationTiming = entries as PerformanceNavigationTiming;
// entriesNavigationTiming.type === 'reload'

const refreshToken = localStorage.getItem('refreshToken');
if (!isAuthorized && refreshToken) {
refresh(refreshToken as string);
}
if (!isAuthorized && refreshToken) refresh(refreshToken as string);
}, [isAuthorized, refresh]);

return <div>{children}</div>;
Expand Down
32 changes: 32 additions & 0 deletions components/withAuth.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
'use client';

import { useRouter } from 'next/navigation';
import { useEffect } from 'react';
import { useAuthStore } from '@/stores/authStore';

export interface WithAuthProps {} // 추후에 인증 과정에 더 필요한 props를 위해

export default function withAuth<T extends WithAuthProps = WithAuthProps>(
Component: React.ComponentType<T>,
) {
const ComponentWithAuth = (props: Omit<T, keyof WithAuthProps>) => {
const isAuthorized = useAuthStore((state) => state.authInfo.isAuthorized);
const isLoading = useAuthStore((state) => state.authInfo.isLoading);
const router = useRouter();

useEffect(() => {
// 가장 초기 상태에는 undefined이므로, 해당 경우를 고려 해주어야 함
if (isLoading !== undefined && !isLoading && !isAuthorized) {
router.push('/login');
}
});

return !isLoading && isAuthorized ? (
<Component {...(props as T)} />
) : (
<div className="">loading</div> // 렌더링과 라우팅 사이의 딜레이 시 보여질 화면
);
};

return ComponentWithAuth;
}
11 changes: 8 additions & 3 deletions hooks/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export const useAuth = () => {
const setAuthInfo = useAuthStore((state) => state.setAuthInfo);

const login = async (provider: string, code: string) => {
setAuthInfo({ isLoading: true });
const res = await fetch(
`${process.env.NEXT_PUBLIC_SERVER_BASE_URL}/v1/login/${provider}?code=${code}`,
{ cache: 'no-store' },
Expand All @@ -15,13 +16,15 @@ export const useAuth = () => {
if (res.ok) {
const result: TAuthInfo = await res.json();
localStorage.setItem('refreshToken', result.refreshToken as string);
setAuthInfo(result);
setAuthInfo({ ...result, isAuthorized: true, isLoading: false });
return result;
}
setAuthInfo(null);
return false;
};

const refresh = async (token: string) => {
setAuthInfo({ isLoading: true });
const headers = new Headers();
headers.set('Authorization', `Bearer ${token}`);
const res = await fetch(
Expand All @@ -31,15 +34,16 @@ export const useAuth = () => {
if (res.ok) {
const result: TAuthInfo = await res.json();
localStorage.setItem('refreshToken', result.refreshToken as string);
setAuthInfo(result);
return res.json();
setAuthInfo({ ...result, isAuthorized: true, isLoading: false });
return result;
}
localStorage.removeItem('refreshToken');
setAuthInfo(null);
return false;
};

const logout = async (provider: string, token: string) => {
setAuthInfo({ isLoading: true });
const headers = new Headers();
headers.set('Authorization', `bearer ${token}`);
const res = await fetch(
Expand All @@ -52,6 +56,7 @@ export const useAuth = () => {
setAuthInfo(null);
return true;
}
setAuthInfo({ isLoading: false });
return false;
};

Expand Down
5 changes: 2 additions & 3 deletions stores/authStore.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ interface TUseAuth {

const initialState: TAuthInfo = {
isAuthorized: false,
isLoading: false,
id: null,
nickName: null,
email: null,
Expand All @@ -23,9 +24,7 @@ export const useAuthStore = create(
authInfo: initialState,
setAuthInfo: (payload) =>
set((state) => ({
authInfo: payload
? { ...state.authInfo, ...payload, isAuthorized: true }
: initialState,
authInfo: payload ? { ...state.authInfo, ...payload } : initialState,
})),
})),
);
1 change: 1 addition & 0 deletions types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export interface TQna {
}

export interface TAuthInfo {
isLoading: boolean;
isAuthorized: boolean;
id: number | null;
nickName: string | null;
Expand Down

0 comments on commit 11c973c

Please sign in to comment.