덕구공 2022. 6. 17. 06:21

Why?

  • UX적 관점에서 생각할 때, 래처럼 로그인하지 않은 사용자가 인증이 필요한 페이지에 접속하려고 할때 로그인 화면으로 넘어가서 로그인을 마친 후 다시 원래 가고자했던 페이지로 돌아오는 것은 사용자의 편의를 위해서도 매우 중요하다!

  • 만약 인증된 사용자만 사용할 수 있는 페이지를 사용하려고 할 때, 로그인을 하지 않은 상태이거나 jwt-token이 유효하지 않으면 로그인 화면으로 가서 로그인에 성공하면 다시 원래 화면으로 돌아올 수 있게 리다이렉트하게 할 수 있게 Navigate 컴포넌트(react-router-v6)의 url에 쿼리 파라미터로 기존에 사용하고자하는 페이지의 url을 넘겨주자.
  • 만약 로그인이 된 상태라면 기존에 이용하고자 하는 페이지의 컴포넌트를 리턴해서 렌더링한다.
  • 즉, PrivateRoute 컴포넌트는 props로 원래 가고자 하는 url과 보여주고자한 컴포넌트를 받는다!

PrivateRoutes.js

import React from "react";
import { Navigate } from "react-router-dom";
import { jwtUtils } from "../utils/JwtUtils";
import { useRecoilState, useRecoilValue } from "recoil";
import { tokenState } from "../recoil/store";

const PrivateRoute = (props) => {
  // 넘어오는 props를 파악하는게 중요.
  // path, component ....
  // recoil에 토큰의 정보가 담겨있다!
  const [token, setToken] = useRecoilState(tokenState);
  const { component: RouteComponent, path } = props;
  // 토큰의 검증이 성공하면 redirectUrl은 로그인이 성공후 돌아갈 화면이다.
  if (!jwtUtils.isAuth(token)) {
    alert("로그인이 필요한 페이지입니다");
    return <Navigate to={`/login?redirectUrl=${path}`} />;
  }
  return <RouteComponent />;
};

export default PrivateRoute;

PrivateRoutes를 사용할 컴포넌트

  • PrivateRoute는 아래처럼 사용하면 된다!! props로 원래 가고자했던 url과 보여주고자했던 컴포넌트를 넘겨주자
  • 즉, 사용자가 /add-magazine경로에서 AddMagazine 컴포넌트를 보려 한 것이다
import PrivateRoute from "./routes/PrivateRoutes";
...
return(
  ...
  <Route
     path="/add-magazine"
     element={<PrivateRoute path="/add-magazine" component={AddMagazine} />}
  />;
)

export default App;

로그인 컴포넌트

  • 로그인 페이지에서 로그인이 성공하면 아래처럼 쿼리 파라미터로 넘겨준 redirectUrl=/add-magazine을 useSearchParams 훅으로 파싱해서 useNavigate 훅으로 /add-magazine 경로로 이동시키자!

...

const navigate = useNavigate();
const [searchParams, setSearchParams] = useSearchParams();

....


const submit = async (values) => {
  const { email, password } = values;
  try {
    const { data } = await axios.post("http://13.125.145.83/api/login", {
      email,
      password,
    });
    await setToken(data["Access-Token"]);
    const redirectUrl = searchParams.get("redirectUrl");
    // PrivateRoute를 통해 로그인 페이지에 접속하면 redireUrl로 이동하고
    if (redirectUrl) {
      navigate(redirectUrl);
    // 그렇지 않고, 로그인 페이지에 집적 접속하면 홈화면으로 이동하자
    } else {
      navigate("/");
    }
  } catch (e) {
    toast.error(
      <div>
        로그인에 실패하였습니다!
        <br />
        아이디와 패스워드를 확인해주세요!
      </div>,
      {
        position: "top-center",
      }
    );
  }
};

 

+++ 만약 URI 파라미터나 쿼리 스트링이 존재하면!

  • 아래처럼 useLocation 훅을 이용해 그냥 주소를 넘겨주자!!

URI 파라미터

...

const location = useLocation();

...

<Route
  path="/edit-magazine/:id"
  element={
    <PrivateRoute path={`${location.pathname}`} component={EditMagazine} />
  }
/>

쿼리 스트링

...

const location = useLocation();

...

<Route
  path="/edit-magazine"
  element={
    <PrivateRoute path={`${location.pathname}`} component={EditMagazine} />
  }
/>