private route 구현
jwt token의 유효성을 검증하는 유틸리티 클래스를추가한다.
src/utils/JwtUtils.ts
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | import jwtDecode from "jwt-decode"; export class jwtUtils {   static isAuth(token: any) {     if (!token) {       return false;     }     const decoded: any = jwtDecode(token);     // console.log(decoded);     if (decoded.exp > new Date().getTime() / 1000) {       return true;     } else {       return false;     }   } }   | 
routes 폴더에 라우팅 패스를 명시한다.
src/routes/index.js
| 1 2 3 4 5 6 7 8 | export const ROUTES_PATH = {   Main: "/",   BoardRegister: "/board-register",   BoardView: "/board-view/:id",   BoardEdit: "/board-edit/:id",   Login: "/login",   SignUp: "/signUp" } | 
PrivateRoute 컴포넌트를 생성한다. 이 컴포넌트는 인증된 사용자만 통과시킨다.
src/routes/PrivateRoute.jsx
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | import React from 'react'; import {Redirect, Route} from "react-router-dom"; import {useSelector} from "react-redux"; import {ROUTES_PATH} from "./index"; import {jwtUtils} from "../utils/jwtUtils"; const PrivateRoute = (props) => {   // BrowseRouter로 부터 넘어오는 props를 파악하는게 중요.   // path, location ...   console.log(props);   const { component: RouteComponent, ...rest } = props;   const token = useSelector(state => state.Auth.token);   // 아래 view가 리턴되지 않도록 한다.   // redirectUrl은 로그인이 성공후 돌아갈 화면이다.   if (!jwtUtils.isAuth(token)) {     return <Redirect to={`${ROUTES_PATH.Login}?redirectUrl=${props.path}`} />   }   return (     <Route       {...rest}       render = {         routeProps => <RouteComponent {...routeProps} />       }     />   ); } export default PrivateRoute | 
인증 로직 적용
App.jsx에 인증 로직을 적용한다.
useEffect 훅에서 token을 가져와서 유효성을 검증하고 isAuth 상태를 정의한다. 이 상태를 가지고 우측 상단 로그인 혹은 로그아웃 버튼을 구현한다.
라우팅에서 게시판 글등록과 게시판 수정에는 인증로직이 필요하므로, Route가 아니라 앞에서 만든 PrivateRoute를 적용하였다.
src/App.jsx
		
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | function App(props: any) {   const [isAuth, setIsAuth] = useState(false);   const dispatch = useDispatch();   const token = useSelector((state: any) => state.Auth.token);   useEffect(() => {     if (jwtUtils.isAuth(token)) {       setIsAuth(true);     } else {       setIsAuth(false);     }   }, [token]);   const logout = () => {     dispatch(setToken(''));   }   return (     <>       <BrowserRouter>         <Container fluid className="p-0">           <Navbar bg="dark" variant="dark" expand="lg">             <Link to="/" className="navbar-brand">HOME</Link>             <Navbar.Toggle aria-controls="basic-navbar-nav" />             <Navbar.Collapse id="basic-navbar-nav">               <Nav className="mr-auto flex-grow-1">                 <Link to="/board-list" className="nav-link">게시판</Link>                 <Link to="/board-register" className="nav-link">글등록</Link>                 <span className="flex-grow-1"></span>                 {                   isAuth ? <Nav.Link onClick={logout}>로그아웃</Nav.Link> :                     <Link to="/login" className="nav-link">로그인</Link>                 }               </Nav>             </Navbar.Collapse>           </Navbar>         </Container>         <Container fluid className="px-3 py-2">           <Switch>             <Route exact path="/" component={Home}></Route>             <Route path="/board-list" component={BoardList}></Route>             <PrivateRoute path="/board-register" component={BoardRegister}></PrivateRoute>             <Route path="/board-view/:id" component={BoardView}></Route>             <PrivateRoute path="/board-edit/:id" component={BoardEdit}></PrivateRoute>             <Route path="/login" component={Login}></Route>             <Route path="/sign-up" component={SignUp}></Route>           </Switch>         </Container>       </BrowserRouter>       <ToastContainer />     </>   ); } | 
