[토이 프로젝트] 장미전쟁 score tracker 만들기: react-router-dom의 Outlet 이용하여 마이페이지 접근 권한 설정, 로그아웃 구현

이민선(Jasmine)·2023년 5월 30일
0
post-thumbnail

지난 포스팅에서 로그인 성공 시 my page로 리디렉트하는 것까지 성공했다.

그런데 2가지 미해결 문제가 남아있었다.

[🧐 미해결 상태]

  • 로그인을 하지 않은 상태에서 url에 직접 /mypage path를 입력하고 엔터를 누르면 mypage로 이동한다. 즉 접근 제한이 불가능함.
  • 로그인하고 마이페이지에 왔을 때 "000님" 하고 이름을 띄워주는데, useState에 상태를 저장하다보니 마이페이지에서 유저가 새로고침하면 더 이상 이름이 뜨지 않음.

userName 세션 스토리지에 저장

일단 2번째 문제부터 해결해보자. 그동안 local storage에 setItem 했던 것처럼, session storage에도 같은 방법으로 이름을 저장하면 새로고침해도 user 이름이 저장되지 않을까? 한 번 시도해보자!

// handleGoogleLogin 내부에 아래와 같은 코드 추가
          if (user.displayName) {
            sessionStorage.setItem("userName", user.displayName);
          }

user의 displayName 속성이 존재할 경우 userName이라는 key로 세션 스토리지에 저장!
(if문은 타입 가드이다.)

이제 로그인에 성공하면 세션 스토리지에 userName이라는 key도 뜬다!
이 key를 가지고 세션 스토리지에서 이름을 불러와서 화면에 띄워보자.

function MyPage() {
  // 세션 스토리지에서 userName 가져오기
  const userName = sessionStorage.getItem("userName");
  return (
    <>
      <GameTitleContainer>
        // 화면에 userName 렌더링
        <GameTitle>{userName}</GameTitle>
//...(생략)

음 어렵지 않군! 이제 새로고침해도 user의 이름이 화면에 잘 출력된다.

[✅ 해결]

  • 로그인하고 마이페이지에 왔을 때 "000님" 하고 이름을 띄워주는데, useState에 상태를 저장하다보니 마이페이지에서 유저가 새로고침하면 더 이상 이름이 뜨지 않음.

[🧐 미해결 상태]

  • 로그인을 하지 않은 상태에서 url에 직접 /mypage path를 입력하고 엔터를 누르면 mypage로 이동한다. 즉 접근 제한이 불가능함.


ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ 님하 좋은 하루 보내시긔 ~

로그인을 하지 않은 상태에서 mypage path를 주소창에 직접 입력해서 들어가면 세션 스토리지에 userName이 없기 때문에 아무 이름도 뜨지 않는다.

내가 원하는 건 mypage를 로그인도 하지 않고 감히 접근하려 할경우 접근을 못 하게 하는 것이다.

중첩 Route와 Outlet을 이용하여 로그인 여부에 따른 page 접근 권한 지정

아래 자료를 참고해보고 PrivateRoutes 컴포넌트를 생성해보았다.
https://medium.com/@dennisivy/creating-protected-routes-with-react-router-v6-2c4bbaf7bc1c
https://www.youtube.com/watch?v=2k8NleFjG7I

Outlet? 어디서 많이 들어봤는데? 이번 기회에 공부해보고 요긴하게 써봐야겠다.
일단 React-router-dom 공식문서를 한번 보자면

저 Dashboard 컴포넌트에서 return하는 Outlet이라는 컴포넌트가 무엇이 될지는 중첩된 자식 컴포넌트들 중에서 상대경로에 따라 결정되는 것이다. Dashboard라는 부모 컴포넌트의 path를 /이라고 지정했으므로, 현재 상대경로가 /messages면 DashboardMessages라는 컴포넌트를, /tasks일 때는 DashboardTasks를 렌더링한다. 이때 저 <h1>Dashboard</h1> 내부의 글자는 상대경로와 무관하게 계속 보이게 될 것이다.

그래서 이 Outlet을 이용하여 로그인한 유저만 접근 가능한 Route도 구현할 수 있다.
PrivateRoutes 컴포넌트를 생성하고, isLoggedIn이라는 boolean 값으로 조건 분기하여 을 return할지, 혹은 강제로 Home 컴포넌트로 Navigate할지 결정하는 것이다.

PrivateRoutes.tsx

import { Navigate, Outlet } from "react-router-dom";

function PrivateRoutes() {
  const storedValue = sessionStorage.getItem("isLoggedIn");
  const isLoggedIn: boolean = storedValue === "true";

  // 로그인 안 했으면 좋은말로 할 때 Home으로 가라잉?
  return isLoggedIn ? <Outlet /> : <Navigate to='/' />;
}
export default PrivateRoutes;

로그인에 성공하면 세션 스토리지에 isLoggedIn이라는 key로 true라는 string 값을 저장하고, true일 경우 Outlet을 이용하여 중첩된 자식 Route의 element로 이동할 수 있게한다.

App.tsx

import React from "react";
import { BrowserRouter, Routes, Route } from "react-router-dom";
//...import 생략
import PrivateRoutes from "./common/components/PrivateRoutes/PrivateRoutes";

function App() {
  return (
    <BrowserRouter>
      <Header />
      <Routes>
        // PrivateRoutes를 element로 가진 Route 내부에 중첩된 MyPage 컴포넌트는 유저가 로그인한 상태일 때만 Outlet을 통해서만 접근할 수 있다.
        <Route element={<PrivateRoutes />}>
          <Route path='/mypage' element={<MyPage />} />
        </Route>
        <Route path='/' element={<Home />} />
      </Routes>
    </BrowserRouter>
  );
}

export default App;

아직 로그인하지 않은 상태에서 /mypage에 강제로 접속하려고 하면 응 안돼~하면서 Home으로 redirect해준다.

[✅ 해결]

  • 로그인하고 마이페이지에 왔을 때 "000님" 하고 이름을 띄워주는데, useState에 상태를 저장하다보니 마이페이지에서 유저가 새로고침하면 더 이상 이름이 뜨지 않음.
  • 로그인을 하지 않은 상태에서 url에 직접 /mypage path를 입력하고 엔터를 누르면 mypage로 이동한다. 즉 접근 제한이 불가능함.

둘 다 해결 완료!

Outlet 이거 아주 유용한 친구구만~

이제 마지막으로 로그아웃 구현하면 인증 구현은 마무리 될 듯 하다.

로그아웃 구현

Get Score 버튼과 log out 버튼을 만들어두었다.

log out 먼저 구현해보자구~ 고고슁~

//  handleGoogleLogout 함수
  const handleGoogleLogout = () => {
    const auth = getAuth();
    signOut(auth)
      .then(() => {
      // Home 화면으로 redirect
        navigate("/");
      })
      .catch((error) => {
        console.log(error);
      });
  };

오랜만에 해서 뭔가 어려운 게 있을까봐 걱정했는데 역시 로그아웃은 뚝딱이군.

오늘은 그럼 20000~
이제 develop 브랜치에 merge 하고 씻고 자야겠다 ㅎㅎㅎ 뿌듯한 하루!!!

내일부터는 이제 본격적으로 board를 만들어보는 건가?!!!! 화이팅!!

profile
기록에 진심인 개발자 🌿

0개의 댓글