๋๋ฉํ์ด์ง์ ๋ก๊ทธ์ธํ์ด์ง๋ ํ ํฐ ์์ด๋ ์ ๊ทผํ ์ ์์ด์ผ ํ๊ณ , ๋ง์ดํ์ด์ง์ ํฐ์ผํ ํ์ด์ง๋ ์ธ์ฆ์ด ๋์ด ์๋ ์ํ์์๋ง ์ ๊ทผํ ์ ์์ด์ผ ํ๋ค. ํฐ์ผ QR์ฝ๋ ํ์ด์ง๋ ์ธ์ฆ์ด ๋์ด ์์ง ์์๋ ์ ๊ทผํ ์ ์๋๋ก ํ๋ค. ํ๋ช ์ด ํฐ์ผ์ ์ฌ๋ฌ์ฅ์ ์ฌ์ '๊ณต์ ํ๊ธฐ'๋ฅผ ํตํด ์น๊ตฌ๋ค์๊ฒ ์ค ์ ์์ด์ผ ํ๊ธฐ ๋๋ฌธ์. ๋ผ์ฐํ ๊ณผ ๊ด๋ จ๋ ์ฝ๋๋ ๋ค์๊ณผ ๊ฐ๋ค.
๋ผ์ฐํ
return (
<Routes location={location}>
<Route path="/" element={<Landing />} />
<Route element={<Layout />}>
<Route element={<RefuseAuth />}>
<Route path="/auth/*" element={<AuthRouter />} />
</Route>
<Route element={<RequireAuth />}>
<Route path="/mypage/*" element={<MypageRouter />} />
<Route path="/ticketing/*" element={<TicketingRouter />} />
</Route>
<Route path="/tickets/:ticketId" element={<TicketQR />} />
<Route path="/404" element={<NotFound />} />
</Route>
<Route path="*" element={<Navigate to="/404" />} />
</Routes>
);
๋ฌธ์์์ React-Route-dom ๋ง์ ์ด์ฉํด์ ์ ๊ทผ์ ์ ํํ๋ ๋ฐฉ์์ ๋ํ ์์๊ฐ ์ ๋์ด ์์ด์ ์ฐธ๊ณ ํ๋ค. 1์ฐจ ํ๋ก์ ํธ์์ ์ฌ์ฉํ๋ HOC๋ก ๋ง๋ค์ด ์ปดํฌ๋ํธ๋ฅผ ์ธ์๋ฅผ ๋๊ธฐ๊ณ ๊ฑธ๋ฌ์ ๋ฆฌํดํ๋ ๋ฐฉ์์ ๋นํด ํจ์ ๊น๋ํ๊ณ ์ง๊ด์ ์ด์ด์ ์ข๋ค.
RequireAuth.tsx
const RequireAuth = () => {
const { pathname } = useLocation();
const setRedirectUri = useSetRecoilState(redirectState);
const accessToken = localStorage.getItem('accessToken');
const registerToken = localStorage.getItem('registerToken');
// undefined or token
useEffect(() => {
setRedirectUri(pathname);
}, []);
if (accessToken) {
// ์ด์ธ์ค ํ ํฐ ์์ผ๋ฉด ํจ์ค
return <Outlet />;
} else if (registerToken) {
// ์ด์ธ์ค ํ ํฐ ์์ด ๋ ์ง์คํฐ ํ ํฐ๋ง ์์ผ๋ฉด ํ์๊ฐ์
return <Navigate replace to="/auth/init" />;
} else {
// ๋ ๋ค ์์ผ๋ฉด ๋ก๊ทธ์ธ..?
return <Navigate replace to="/auth/login/1" />;
}
};
export default RequireAuth;
์คํํ๊ณ ๊ณต์ฐ๋ ๊น์ง ์ผ์ฃผ์ผ์ ๋ ์งง๊ฒ ์ฌ์ฉํ๋ ์๋น์ค์ด๋ค ๋ณด๋ ๋ฆฌํ๋ ์ฌ ํ ํฐ์ ๊ตณ์ด ์ฌ์ฉํ์ง ์๊ณ ์ด์ธ์คํ ํฐ (์ดํ AT)๋ง ์ฌ์ฉํ๋ค.
RequireAuth
๋ก ๊ฐ์ธ์ง ํ์ด์ง์ ์ ๊ทผํ ๋ AT๊ฐ ์์ผ๋ฉด ํจ์คํ๊ณ , ์์ผ๋ฉด ๋ก๊ทธ์ธ ํ์ด์ง๋ก ๋ณด๋ธ๋ค. ๋ก๊ทธ์ธ์ด ์ฑ๊ณตํ์ ๋ ํ์๊ฐ์
๊น์ง ์๋ฃํ ์ ์ ์ผ ๋๋ AT๋ฅผ ๋ฆฌ์คํฐ์ค๋ก ์ฃผ์ง๋ง, ํ์๊ฐ์
์ ํ์ง ์์ ์ฒซ 1ํ ๋ก๊ทธ์ธ์ผ๋๋ ๋ ์ง์คํฐ ํ ํฐ์ ๋ฐ๋๋ค. ๊ทธ๋ด๋ ํ์๊ฐ์
ํ์ด์ง๋ก ๋ณด๋ด๋ฒ๋ฆฌ์.
๋๋ฉํ์ด์ง์์ '์๋งคํ๋ฌ ๊ฐ๊ธฐ' ๋๋ '์๋งค ๋ด์ญ ๋ณด๊ธฐ' ๋ฅผ ๋๋ ์ ๋ ๊ทธ ๋ชฉ์ ์ง๋ฅผ ๊ธฐ์ตํ๊ณ ์๋ค๊ฐ ๋ก๊ทธ์ธ์ด ๋๋ ํ์ ์๋ ๋ชฉ์ ์ง๋ก ๊ฐ๋๋ก ํด์ผํ๋ค. redirectUri
๋ผ๋ ์ํ์ ์ ์ฅํด๋๊ณ ๋ก๊ทธ์ธ ์ดํ์ ํด๋น ๊ฐ์ ๊ฐ์ ธ์ ๋ค๋น๊ฒ์ดํธ ์์ผ์ฃผ์๋ค.
RefuseAuth.ts
const RefuseAuth = () => {
const { openModal, closeModal } = useModal();
const accessToken = localStorage.getItem('accessToken');
const registerToken = localStorage.getItem('registerToken');
// undefined or token
const location = useLocation();
if (accessToken) {
// ์ด์ธ์ค ํ ํฐ ์์ผ๋ฉด ๋ง์ดํ์ด์ง๋ก ๋๋๋ ค๋ฒ๋ฆผ
// ์๋ฌ์ฒ๋ฆฌ ๋ก์ง (์๋ต)
return <Navigate replace to="/mypage" />;
} else if (location.pathname === '/auth/init') {
// auth/init ์ ๊ทผ์ผ๋, ๋ ์ง์คํฐ ํ ํฐ ์์ด์ผ๋ง ์ ๊ทผ ๊ฐ๋ฅ
if (registerToken) {
return <Outlet />;
} else {
// ์๋ฌ ์ฒ๋ฆฌ ๋ก์ง (์๋ต)
return <Navigate replace to="/auth/login/1" />;
}
} else {
// ๋ ๋ค ์์ผ๋ฉด ๋ก๊ทธ์ธ ํ์ด์ง๋ก ๊ทธ๋ฅ ํจ์ค
return <Outlet />;
}
};
export default RefuseAuth;
๋ก๊ทธ์ธ์ ํ๊ณ ํฐ์ผ ์๋งค๋ ๋ง์ดํ์ด์ง๋ก ๋ค์ด์์๋, ๋ค๋ก๊ฐ๊ธฐ๋ฅผ ๋ฐฉ์งํ๋ ๋ก์ง์ด๋ค. ํ์๊ฐ์ ํ๋ ๋ถ๋ถ์ ๋ ์ง์คํฐ ํ ํฐ์ ๋ฐ๋ก ์ฌ์ฉํ๊ธฐ ๋๋ฌธ์ ๋ฐ๋ก ์ฒ๋ฆฌ๋ฅผ ํด์ฃผ์๋ค.
Axios ์ค์
export const axiosPublic = axios.create({
baseURL: BASE_URL,
headers: { 'Content-Type': 'application/json' },
});
export const axiosPrivate = axios.create({
baseURL: BASE_URL,
headers: { 'Content-Type': 'application/json' },
});
AT๋ฅผ ์ฌ์ฉํ๋ axiosPrivate๊ณผ, ์ฌ์ฉํ์ง ์๋ axiosPublic ๋ ๊ฐ์ ์ธ์คํด์ค๋ฅผ ๋ง๋ค์ด ๋ฐ๋ก ์ฌ์ฉํ๋ค.
Recoil
const initialState = {
isAuthenticated: false,
registerToken: null,
phoneNumber: null,
inProcess: false,
};
const getTokenFromLocalStorage = (): IAuthType => {
const accessToken = localStorage.getItem('accessToken');
const registerToken = localStorage.getItem('registerToken');
if (accessToken) {
// ์ด์ธ์คํ ํฐ์ด ์์ผ๋ฉด axios ์ธ์คํด์ค์ ์ปค๋จผ ํค๋๋ก ์ง์ด๋ฃ์
axiosPrivate.defaults.headers.common[
'Authorization'
] = `Bearer ${accessToken}`;
//์๋ก๊ณ ์นจํ ๋๋ง๋ค ํ ํฐ์ผ๋ก ์ ์ ์ ๋ณด(์
๊ธ์๋ช
, ์ ํ๋ฒํธ) ๊ฐ์ ธ์ค๋ ๊ณผ์ ํ์
return {
...initialState,
isAuthenticated: true,
registerToken,
};
} else return { ...initialState, registerToken };
};
export const authState = atom<IAuthType>({
key: 'auth',
default: getTokenFromLocalStorage(),
});
๋ฆฌ์ฝ์ผ์์ authState
๋ฅผ ์ฒ์ ์ด๊ธฐํํ ๋ ์ฟ ํค์ ์๋ ๊ฐ์ ๊ฐ์ ธ์์ default ๊ฐ์ผ๋ก ์ฌ์ฉํ๋ค. AT๊ฐ ์๋ค๋ฉด ์ํ์ ๋ฃ๊ณ axios ์ธ์คํด์ค์ ์ปค๋จผ ํค๋๋ก ์ง์ด ๋ฃ๋๋ค.
์ธ์ฆ์ ํ๊ณ ์ด์ ๋ฐ๋ผ ๋ผ์ฐํ ๊ณผ ์๋ฌ์ฒ๋ฆฌํ๋ ๋ก์ง์ ๋ํด์ ์ ๋ฆฌ๋ฅผ ํด๋ณด์๋ค. ์ด ์ธ์ ์๋ฌ๊ฐ ์๋ ๊ฒฝ์ฐ์๋ ์๋ฆผ ๋ชจ๋ฌ์ ๋์ ์ฌ์ฉ์์๊ฒ ์ ๋ฌํ๋ค. ๋ฆฌ์กํธ ์ฟผ๋ฆฌ๋ฅผ ์ด์ฉํด ์๋ฌ๋ฅผ ๊ณตํต์ผ๋ก ์ฒ๋ฆฌํ๋ ๋ฐฉ๋ฒ๊ณผ, ํ๋ก์ ํธ ๋ด์ ๋ค์ํ ๊ณณ์์ ์ฌ์ฉ๋๋ ๋ชจ๋ฌ์ ๋์ฐ๋ ๋ฐฉ๋ฒ๋ ์ฐจ์ฐจ ์ ๋ฆฌํ ์์ ์ด๋ค.