일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- userManagement
- Token
- RCPS
- 스프링시큐리티
- 공통메서드
- 빌드 및 배포
- 로그인 로직
- ui탬플릿
- 파생상품평가
- register
- 이미지 업로드
- 밸류즈 홈페이지
- 회원가입로직
- 관리자페이지
- mypage
- MRC
- react
- 인증처리
- jsonwebtoken
- Styled Components
- 달력 라이브러리
- stock option
- 마이페이지
- 밸류즈
- 캘린더 라이브러리
- 로그인
- Update
- 배포
- Ajax
- Typesciprt
- Today
- Total
I T H
[MySchedule project] 8. 인증에 의한 header, Route 로직 / 로그아웃 본문
로그인 및 인증 처리 완료시 리덕스 스토어에 변수 isAuth 가 true로 바뀌는 것까지 했다면
이번 챕터에서는 isAuth or Role의 값에 의해 페이지경로가 다르게 처리되는 로직을 하겠다.
즉, 관리자 페이지 or 로그인 or 로그인이 안했을경우 페이지가 각각 다르게 처리되야 하므로,
redux store에 있는 값들(isAuth, role의 값)을 불러와서 header부분과 app.tsx의 route부분을 각각 처리해주자!
Frontend
[ src / layout / Header / index.tsx ]
- 먼저 redux의 useSelector 훅을 사용해서 isAuth의 값과 role의 값을 불러온다.
- auth가 true이면 로그인이 완료되었기에 마이페이지와 로그아웃이 보이게 하고, 반대의 경우에는 로그인과 회원가입이 보이게 하였다.
- auth가 true이고 role이 1인 경우는 관리자로 처리했기에 관리자만 볼수있는 페이지만 뜨도록 구현하였다.
import React from "react";
import { Link, useNavigate } from "react-router-dom";
import { AiOutlineSchedule } from "react-icons/ai";
import { useAddDispatch, useAddSelector } from "../../store/redux";
import { logout } from "../../store/thunkFunction";
const Header = () => {
const dispatch = useAddDispatch();
const navigate = useNavigate();
const auth = useAddSelector((state) => state.user?.isAuth);
const userData = useAddSelector((state) => state.user?.userData);
const role = useAddSelector((state) => state.user?.userData?.role);
//로그아웃
const handleLogout = () => {
dispatch(logout()).then(() => {
navigate("/login");
});
};
return (
<section>
<nav className="bg-white border-gray-100 border-b-[1px]">
<div className="flex flex-wrap justify-between items-center mx-auto max-w-screen-sm sm:max-w-screen-xl p-4">
<p className="flex items-center space-x-3 rtl:space-x-reverse">
<AiOutlineSchedule className="h-8 text-gray-800 dark:text-gray-900 w-10 float-left" />
<span className="self-center sm:text-2xl text-lg font-semibold whitespace-nowrap dark:text-gray-900">
<Link to={"/"}>MY-SCHEDULE</Link>
</span>
</p>
<div className="flex items-end space-x-6 rtl:space-x-reverse mt-2">
{auth ? (
<>
<p
className="text-sm font-medium font-sans text-gray-800 dark:text-gray-900 hover:text-gray-600"
aria-current="page"
>
<Link
to={"/mypage"}
>{`${userData.userName}님`}</Link>
</p>
<p className="text-sm font-medium font-sans text-gray-800 dark:text-gray-900 hover:text-gray-600">
<button onClick={handleLogout}>로그아웃</button>
</p>
</>
) : (
<>
<p className="text-sm font-medium font-sans text-gray-800 dark:text-gray-900 hover:text-gray-600">
<Link to={"/register"}>회원가입</Link>
</p>
<p className="text-sm font-medium font-sans text-gray-800 dark:text-gray-900 hover:text-gray-600">
<Link to={"/login"}>로그인</Link>
</p>
</>
)}
</div>
</div>
</nav>
{auth === true && (
<nav className="border-gray-100 border-b-[1px] ">
<div className="max-w-screen-xl px-4 py-4 mx-auto">
<div className="flex items-center">
<ul className="pl-1 flex flex-row font-medium mt-0 space-x-8 rtl:space-x-reverse text-sm">
<li>
<p
className="font-medium text-gray-800 dark:text-gray-900 hover:text-gray-600"
aria-current="page"
>
<Link to={""}>운동관리</Link>
</p>
</li>
<li>
<p className="font-medium text-gray-800 dark:text-gray-900 hover:text-gray-600">
<Link to={"/myschedule"}>스케줄관리</Link>
</p>
</li>
<li>
<p className="font-medium text-gray-800 dark:text-gray-900 hover:text-gray-600">
<Link to={""}>식비관리</Link>
</p>
</li>
<li>
<p className="font-medium text-gray-800 dark:text-gray-900 hover:text-gray-600">
<Link to={""}>메모</Link>
</p>
</li>
{/* 관리자 1 사용자 0 */}
{role === 1 && (
<>
<li>
<p className="font-medium text-gray-800 dark:text-gray-900 hover:text-gray-600">
<Link to={"/userManagement"}>사용자관리</Link>
</p>
</li>
<li>
<p className="font-medium text-gray-800 dark:text-gray-900 hover:text-gray-600">
<Link to={""}>로그관리</Link>
</p>
</li>
</>
)}
</ul>
</div>
</div>
</nav>
)}
{/* object-cover : 이미지를 왜곡없이 보여줌
bottom-0 inset-x-0 text-center: absolute 시에 텍스트의 가운데정렬 text-center만 사용시 안먹힘.
opacity : 배경흐리게
*/}
<div className="m-auto relative">
<div className="absolute top-[50%] bottom-0 inset-x-0 text-center">
<h2 className="text-gray-900 font-sans font-bold text-xl">
{" "}
마이스케줄과 함께 다양한 일정을 관리해보세요{" "}
</h2>
</div>
<div>
<img
src="/img/backImage1.avif"
alt=""
className="w-full max-h-64 opacity-45 object-cover"
/>
</div>
</div>
</section>
);
};
export default Header;
[ App.tsx ]
- route 경로에 대한 코드 역시 리덕스 스토어에서 isAuth와 role을 불러와서 구현하였음.
- 3가지 컴포넌트로 보내서 조건식을 넣어 처리하였다.
1. AuthenticatedPage 컴포넌트로 props "isAuth"를 보내 true일 경우 Outlet을 넣어 하위 route들을 타게 하였음.
2. NotAuthenticatedPage 컴포넌트로 props "isAuth"를 보내 false일 경우 Outlet을 넣어 하위 route들을 타게 하였음.
3. ManagerPage 컴포넌트로 props "role"를 보내 1일 경우 Outlet을 넣어 하위 route들을 타게 하였음.
import React, { useEffect } from "react";
import "./App.css";
import { Outlet, Route, Routes, useLocation } from "react-router-dom";
import MainPage from "./pages/MainPage";
import Footer from "./layout/Footer";
import Header from "./layout/Header";
import Login from "./pages/Login";
import Register from "./pages/Register";
import { ToastContainer } from "react-toastify";
import { useAddDispatch, useAddSelector } from "./store/redux";
import { authCheck } from "./store/thunkFunction";
import Mypage from "./pages/Mypage";
import UserManagement from "./pages/UserManagement";
import ManagerPage from "./pages/RouteComponent/ManagerPage";
import AuthenticatedPage from "./pages/RouteComponent/AuthenticatedPage";
import NotAuthenticatedPage from "./pages/RouteComponent/NotAuthenticatedPage";
function Layout() {
return (
<div className="flex flex-col justify-between">
{/* toast 라이브러리사용 */}
<ToastContainer
position="bottom-left"
theme="light"
pauseOnHover
autoClose={1500}
/>
<Header />
<main className="mb-auto w-10/12 mx-auto">
<Outlet />
</main>
<Footer />
</div>
);
}
function App() {
const isAuth = useAddSelector((state) => state.user?.isAuth);
const role = useAddSelector((state) => state.user?.userData?.role);
const dispatch = useAddDispatch();
const { pathname } = useLocation(); //현재주소 경로
//인증이 잘되었는지 체크
useEffect(() => {
if (isAuth) {
dispatch(authCheck());
}
}, [isAuth, dispatch, pathname]);
return (
<Routes>
<Route path="/" element={<Layout />}>
<Route index element={<MainPage />} />
{/* 인증O - 관리자만 */}
<Route element={<ManagerPage role={role} />}>
<Route path="userManagement" index element={<UserManagement />} />
</Route>
{/* 인증O - 일반유저 - 로그인 했을때 */}
<Route element={<AuthenticatedPage isAuth={isAuth} />}>
<Route path="mypage" index element={<Mypage />} />
</Route>
{/* 인증X - 일반유저 - 로그인 안했을때 */}
<Route element={<NotAuthenticatedPage isAuth={isAuth} />}>
<Route path="register" index element={<Register />} />
<Route path="login" index element={<Login />} />
</Route>
</Route>
</Routes>
);
}
export default App;
[ pages / RouteComponent / AuthenticatedPage.tsx ]
import React from "react";
import { Navigate, Outlet } from "react-router-dom";
const AuthenticatedPage = ({ isAuth }: { isAuth: boolean }) => {
return isAuth ? <Outlet /> : <Navigate to={"/"} />;
};
export default AuthenticatedPage;
[ pages / RouteComponent / NotAuthenticatedPage.tsx ]
import React from "react";
import { Navigate, Outlet } from "react-router-dom";
const NotAuthenticatedPage = ({ isAuth }: { isAuth: boolean }) => {
return !isAuth ? <Outlet /> : <Navigate to={"/"} />;
};
export default NotAuthenticatedPage;
[ pages / RouteComponent / ManagerPage.tsx ]
import React from "react";
import { Navigate, Outlet } from "react-router-dom";
const ManagerPage = ({ role }: { role: number }) => {
return role === 1 ? <Outlet /> : <Navigate to={"/"} />;
};
export default ManagerPage;
- 로그아웃 로직
[ src / layout / Header / index.tsx ]
- 로그아웃 버튼 이벤트시 handleLogout 함수 실행
- 로그아웃 정상 작동 후 login페이지로 이동
//로그아웃
const handleLogout = () => {
dispatch(logout()).then(() => {
navigate("/login");
});
};
Backend
[ index.js ]
- route 경로 추가
//route start
app.use("/logout", require("./routes/logout"));
//route end
[ routes/ logout.js ]
const express = require("express");
const auth = require("../middleware/auth");
const router = express.Router();
//로그아웃
router.post("/", auth, async (req, res, next) => {
try {
return res.sendStatus(200);
} catch (error) {
next(error);
}
});
module.exports = router;
Frontend
[ src / store / userSlice.tsx ]
- 로그아웃 정상작동시에는 isAuth를 false로 하고 store의 userData부분을 초기화해준다.
- localStorage에 넣어놨던 토큰도 지워준다.
.addCase(logout.pending, (state) => {
state.isLoading = true;
})
.addCase(logout.fulfilled, (state) => {
state.isLoading = false;
state.userData = initialState.userData; //초기화
state.isAuth = false;
localStorage.removeItem("accessToken");
})
.addCase(logout.rejected, (state, action: any) => {
state.isLoading = false;
state.error = action.payload;
toast.error(action.payload);
})
[ 결과화면 ]
- 관리자 접속 화면

- 일반 사용자 접속 화면

- url Test : 로그인이 안되어있을때 url로 mypage 접속시 mypage로 안들어가지고 메인페이지로 이동하면 정상작동

- 로그아웃 되었을 때 리덕스 화면

'React + Node.js' 카테고리의 다른 글
[MySchedule project] 10. 마이페이지 로직(2) - 이미지(파일) 업로드 (0) | 2024.02.01 |
---|---|
[MySchedule project] 9. 마이페이지 로직(1) - 조회, 업데이트 (1) | 2024.02.01 |
[MySchedule project] 7. JWT(json web token) / 로그인 로직(2) (2) | 2024.01.30 |
[MySchedule project] 6. JWT(json web token) / 로그인 로직(1) (2) | 2024.01.30 |
[MySchedule project] 5. backend - 회원가입 로직 (0) | 2024.01.25 |