웹 어플리케이션을 개발하다 보면 사용자의 권한에 따라 페이지의 접근을 막아야하는 경우가 자주 발생한다.
예를 들면, 로그인을 하지 않은 사용자가 방문하면 안 되는 페이지가 있을 수 있다. 페이지를 이동하는 네비게이션 바의 버튼을 클릭 시 항상 로그인 유무를 파악하여 접근을 막을 수 있다.
하지만 이는 사용자가 주소창을 통해 개발자의 의도와 다르게 비정상적으로 접근하는 경우를 막을 수 없다.
이를 해결하기 위해 페이지 컴포넌트에서 useEffect를 사용하여 로그인 유무를 판단하고, 로그인이 되지 않았다면 페이지를 나가도록 구현하는 등을 생각할 수 있지만 이 방법의 단점은 페이지를 일단 무조건 한 번 들어간다는 것이다.
예를 들어, 페이지 이동이 완료 된 후 사용자의 로그인 유무를 판단하여 로그인 페이지로 이동하게 하거나, alert를 띄워 사용자에게 로그인을 권유한다는 것이다.
이는 사용자 경험을 저해할 수 있고, 각 컴포넌트마다 useEffect에 로그인을 판단하는 로직을 구현해야한다. 매우 비효율적이고 별로 좋지 않은 방법이라는 것을 알 수 있다.
따라서 react-router-dom을 사용하여 이를 막는 방법을 사용해보았다.
// app.js
function App() {
const context = useContext(userContext);
const location = useLocation();
const access = context.state.userInfo.username;
const { setUserInfo } = context.actions;
const token = sessionStorage.getItem("Authorization");
...(생략)
return (
<ThemeProvider theme={theme}>
<div className="App">
<GlobalStyle/>
<Helmet>
...(생략)
</Helmet>
<Content>
<AnimatePresence exitBeforeEnter>
...(생략)
<Route path="/viewer/room" element={<PrivateRoute component={<RoomViewer/>} authenticated={token}/>}/>
<Route path="/viewer/room/search/:hashtag" element={<PrivateRoute component={<RoomViewer/>} authenticated={token}/>}/>
<Route path="/detail/posting/:postingId" element={<PrivateRoute component={<Detail />} authenticated={token}/>} />
<Route path="/signup" element={<Signup />}></Route>
...(생략)
// PrivateRoute.jsx
import React from 'react';
import { Navigate } from 'react-router-dom';
const PrivateRoute = ({ authenticated, component:Component}) => {
return(
authenticated?Component:<Navigate to="/login" {...alert("로그인이 필요합니다.")}></Navigate>
)
}
export default PrivateRoute;
위의 코드들은 실제로 내가 프로젝트간 사용했던 코드다.
먼저 PrivateRoute.jsx를 설명하면, props로 사용자의 로그인 유무를 파악할 수 있는 authenticated 와 로그인이 되어있는 상태라면 렌더링 할 컴포넌트 component를 받아온다.
그리고 authenticated가 참이라면 Component를 return하고, 거짓이라면 react-router-dom의 Navigate를 사용하여 로그인 페이지로 리다이렉트 하고, alert를 통해 사용자에게 로그인이 필요하다는 경고창을 띄워준다.
app.js를 보면,
<Route path="/viewer/room" element={<PrivateRoute component={<RoomViewer/>} authenticated={token}/>}/>
위와 같이 PrivateRoute를 사용하는데, /viewer/room으로 라우팅이 되었을 때 PrivateRoute 컴포넌트로 먼저 들어가고, 사용자의 로그인 유무를 파악할 수 있는 값인 token을 props로 넘겨주어 로그인 유무를 파악하고, 이에 따라 컴포넌트를 렌더링 하도록 만들 수 있다.