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 /> </> ); } |