사용자의 로그인 상태나 권한에 따라 접근할 수 있는 경로가 다르다. 물론 서버쪽에서 체크를 해주긴 하지만, 해당 URL로 넘어간다는 것 자체를 프론트측에서 막아주는 것이 바람직하다. 그렇기 때문에 React의 라우터를 이용하여 접근 제한(Access Control)을 해주어야 하는데 여기서 필요한 게 Private Route와 Public Route이다.
PrivateRoute는 로그인한 사용자에게 제공되는 루트이고, 만약 로그인하지 않은 사용자가 이 루트로 접근하고자 한다면 로그인 페이지로 Redirection한다.
반면,
PubilcRoute는 로그인 여부와 상관없이 사용자에게 제공되는 루트이다. 이미 로그인한 사용자가 해당 루트로 접근하는 것을 막고자 한다면 restricted 옵션을 줘서 제어할 수 있다.
이 필요한 상황이었다.
로그인 성공을 하게 되면 Django 서버로부터 받은 닉네임 정보를 프론트엔드단에서 'nickname' 이라는 이름으로 sessionStorage에 저장하게 되는데 이를 이용해 로그인 여부를 확인해주는 함수를 만들게 된다.
const isAdmin = () => {
return !!sessionStorage.getItem("nickname");
};
export default isAdmin;
근데 여기서 왜 '!!'를 사용해주는 걸까. 어차피 같은 결과(true나 false)로 돌아오는 것 아닌가 싶었지만
다른 타입의 데이터를 boolean형으로 명시적 형 변환 시키기 위한 용도의 연산자
"" , false, NaN, undefined, null, 0 중 하나일 때 return false
그 외의 나머지 상황은 모두 return true
다음으로 구현을 위해 다음과 같이 PrivateRoute 컴포넌트를 먼저 만들어 주었다.
import React from "react";
import { Route, Redirect } from "react-router-dom";
import isAdmin from "./Admin";
const PrivateRoute = ({ component: Component, ...rest }) => {
return (
// Show the component only when the user is logged in
// Otherwise, redirect the user to /signin page
<Route
{...rest}
render={(props) => {
!isAdmin() &&
alert("접근 권한이 없습니다. 로그인 후 다시 시도하십시오.");
return isAdmin() ? <Component {...props} /> : <Redirect to="/login" />;
}}
/>
);
};
export default PrivateRoute;
로그인 된 상태이면 해당 컴포넌트를 그대로 띄우고, 비로그인 상태일 때는 로그인 페이지로 이동시킨다. 추가적으로 로그인 페이지로 redirect 전에 alert를 띄우도록 작성했다.
다음은 PublicRoute 컴포넌트이다.
import React from "react";
import { Route, Redirect } from "react-router-dom";
import isAdmin from "./Admin";
const PublicRoute = ({ component: Component, restricted, ...rest }) => {
return (
// restricted = false meaning public route
// restricted = true meaning restricted route
<Route
{...rest}
render={(props) =>
isAdmin() && restricted ? <Redirect to="/" /> : <Component {...props} />
}
/>
);
};
export default PublicRoute;
로그인 된 상태(관리자)이면서 restricted가 true일 때, 메인 페이지로 이동된다. 이는 이미 로그인한 유저가 다시 로그인 페이지에 접속하는 상황으로 예를 들 수 있다. 비로그인 상태의 유저일 때는 해당 컴포넌트가 띄워진다.
마지막으로 Router에 적용시킨 코드이다.
const Router = () => {
return(
<BrowserRouter>
<Switch>
<PublicRoute path='/' component={Home} exact></PublicRoute>
<PublicRoute restricted path='/login' component={Login} exact></PublicRoute>
<PublicRoute restricted path='/signup' component={Signup} exact></PublicRoute>
<PrivateRoute path='/storage' component={Storage} exact></PrivateRoute>
<PrivateRoute path='/write/:id' component={Write} exact></PrivateRoute>
<PrivateRoute path='/write' component={Write} exact></PrivateRoute>
<PrivateRoute path='/info' component={Info} exact></PrivateRoute>
<PrivateRoute path='/review' component={Review} exact></PrivateRoute>
</Switch>
</BrowserRouter>
)
}
React 서버를 구동시킨 후 확인해보니 성공적으로 작동함을 확인할 수 있었다.