Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: 토큰 만료 시 자동 로그아웃 후 로그인 페이지로 연결 #79

Open
wants to merge 4 commits into
base: fe
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 12 additions & 6 deletions client/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from 'react';
import React, { useEffect } from 'react';
import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';
import { Provider } from 'react-redux';
import './App.css';
Expand All @@ -21,27 +21,33 @@ import MyPageMain from './pages/MyPageMain';
import MyPageInfo from './pages/MyPageInfo';
import MyPost from './pages/MyPost';

import ProtectedRoute from 'components/ProtectedRoute';

const App: React.FC = () => {
return (
<Provider store={store}>
<div className="App">
<Router>
<AppHeader />
<Routes>
<Route path="/" element={<AllBoardPage />} />

<Route path="/login" element={<Login />} />
<Route path="/signup" element={<SignUpPage />} />
<Route path="/posts/write" element={<EditerPage />} />

<Route path="/" element={<AllBoardPage />} />
<Route path="/free" element={<FreeBoardPage />} />
<Route path="/free/:postId/:userId" element={<FreeDetailPage />} />
<Route path="/auth" element={<AuthBoardPage />} />
<Route path="/auth/:postId/:userId" element={<AuthDetailPage />} />
<Route path="/env" element={<EnvBoardPage />} />

<Route path="/mypage/main" element={<MyPageMain />} />
<Route path="/mypage/info" element={<MyPageInfo />} />
<Route path="/mypage/posts/:postId" element={<MyPost />} />
<Route element={<ProtectedRoute />}>
<Route path="/posts/write" element={<EditerPage />} />

<Route path="/mypage/main" element={<MyPageMain />} />
<Route path="/mypage/info" element={<MyPageInfo />} />
<Route path="/mypage/posts/:postId" element={<MyPost />} />
</Route>
</Routes>
</Router>
</div>
Expand Down
14 changes: 10 additions & 4 deletions client/src/components/GuestHeader.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,32 @@
import React from 'react';
import { Link } from 'react-router-dom';
import { Link, useNavigate } from 'react-router-dom';
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faPencil, faRightToBracket } from "@fortawesome/free-solid-svg-icons";
import { GuestHeaderProps } from 'types/types.ts';
import logo from '../assets/logo.png';

const GuestHeader: React.FC<GuestHeaderProps> = ( { isLoggedIn } ) => {
const GuestHeader: React.FC<GuestHeaderProps> = ({ isLoggedIn }) => {
const navigate = useNavigate();

if (isLoggedIn) {
return null;
}

const handleWriteCilck = () => {
alert('로그인 후 글쓰기가 가능합니다. 로그인 페이지로 이어드릴게요.');
navigate('/login');
};

return (
<header className="header_container">
<div className="header_bar">
<Link to='/' className="header_logo">
<img src={logo} alt="logo" />
</Link>
<div className='header_bar_user'>
<Link to='/login' className="header_icon">
<div onClick={handleWriteCilck} className="header_icon">
<FontAwesomeIcon icon={faPencil} className="header_icon" />
</Link>
</div>
<Link to='/login' className="header_icon">
<FontAwesomeIcon icon={faRightToBracket} className="header_icon" />
</Link>
Expand Down
33 changes: 33 additions & 0 deletions client/src/components/ProtectedRoute.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import React, { useEffect } from 'react';
import { Navigate, Outlet } from 'react-router-dom';

const logout = (): void => {
localStorage.removeItem('accessToekn');
}

const ProtectedRoute: React.FC = () => {
const getAccessToken = (): string | null => {
return localStorage.getItem('accessToken');
}

const isTokenExpired = (token: string | null): boolean => {
if (!token) return true;

const payload = JSON.parse(atob(token.split('.')[1]));
const currentTime = Math.floor(Date.now() / 1000);

return payload.exp < currentTime;
}

const token = getAccessToken();
const isExpired = isTokenExpired(token);

if (isExpired) {
logout();
return <Navigate to="/login" state={{ message: '시간이 오래 지나 로그아웃되었습니다. 다시 로그인해주세요.' }} />;
}

return <Outlet />;
};

export default ProtectedRoute;
2 changes: 1 addition & 1 deletion client/src/pages/LoginPage.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useState } from 'react';
import React, { useState, useEffect } from 'react';
import { postLogin } from 'api/api.js';
import { useDispatch } from 'react-redux';
import { setActiveMenu } from '../store/menuSlice.ts';
Expand Down