로그인 인증 검사를 페이지 진입 이전에 검사하기

김철준·2024년 11월 8일
0

REACT

목록 보기
37/38
post-thumbnail

종택님께서 주최하시는 11월 원티드 프리온보딩 사전과제(TO DO App)를 리팩토링하고 있습니다.

모든 코드는 다음에서 확인하실 수 있어요.
https://github.com/BrightJun96/wanted-pre-onboarding-challenge-fe-27

금일 (2024/11/8) 2회차 강의 때, 다른 분 사전과제 코드 리뷰해주신 부분에 대해서 저도 비슷한 사례의 코드가 있어 이에 대해 개선해보려합니다.

코드리뷰 해주신 부분 중에 좋은 내용이 많았는데요. 그 중, 로그인 인증 검사 시점에 대해 얘기해주셨어요.

로그인 인증 검사 언제 해야하는가?

여기서 말하는 로그인 인증 검사란 로그인을 해야 진입가능한 페이지들에 대한 검사를 말합니다.

구현 사항은 다음과 같아요.

  • 로그인을 해야 접속 가능한 페이지(AuthPage)
    - 할일 페이지 (/todo)
  • 로그인을 하지 않아도 접속 가능한 페이지(NotAuthPage)
    - 로그인(/auth/login),회원가입 페이지(/auth/signup)

AuthPage에 진입할 때,

  • 로그인이 되어있다면 요청 페이지 그대로
  • 로그인이 되어있지않다면 로그인 페이지로 리다이렉트

NotAuthPage에 진입할 때,

  • 로그인이 되어있다면 할일 페이지로 리다이렉트
  • 로그인이 안되어있다면 요청 페이지 그대로

진입이후 인증 검사!

저는 기존에 진입한 이후에 검사를 해주고 검사 실패할 경우, 리다이렉트를 해줬어요.
다음과 같이 최상단 Root 컴포넌트에서 로그인 인증 검사를 하는 useAuth라는 커스텀훅을 호출하고 검사했죠. 모든 컴포넌트에서 어떠한 액션이 있을 때마다 useAuth가 호출되는 것이죠.

코드는 다음과 같아요.

router.ts

import {createBrowserRouter, redirect} from "react-router-dom";
import Login from "../page/login/login.tsx";
import Signup from "../page/signup/signup.tsx";
import Todo from "../page/todo/todo.tsx";
import Root from "../page/root/root.tsx";
import TodoDetails from "../page/todo/details/todoDetails.tsx";
import TodoRegister from "../page/todo/register/todoRegister.tsx";
import {authStorage} from "../helper/auth/authStorage.ts";
import {AuthCheck, authCheck} from "../helper/auth/authCheck.ts";
import {RouteName} from "./routeName.ts";

const router = createBrowserRouter([
    {
        path:"/",
        element:<Root/>,

        children:[
            {
                path: "todo",
                element:<Todo/>,
                children:[
                    {
                        path: ":id",
                        element:<TodoDetails/>
                    },
                    {
                        path: "register",
                        element:<TodoRegister/>
                    }
                ]
            },
            {
                path:"auth",
                children:[
                    {
                        path:"login",
                        element:<Login/>,

                    },
                    {
                        path:"signup",
                        element:<Signup/>
                    }
                ]
            }
        ]
    }

]);


export default router;

Root.tsx

import useAuth from "../../helper/auth/useAuth.ts";
import Header from "../../layout/header/header.tsx";
import {Outlet} from "react-router-dom";

function Root() {
    // 인증 처리
    useAuth()

    return (
        <div>
            <Header/>
            <Outlet/>
        </div>
    );
}

export default Root;

useAuth.ts

import {useLocation} from "react-router-dom";
import {authStorage} from "./authStorage.ts";


function useAuth() {
   const location = useLocation()

   // 페이지
   const loginPage = location.pathname === "/auth/login"
   const signupPage = location.pathname === "/auth/signup"
   const todoPage = location.pathname.includes("/todo")
   const authPage = loginPage || signupPage




   // 로그인 페이지나 회원가입 페이지에 접근했을 때 토큰이 있으면 todo 페이지로 이동
   if(authStorage.getToken()&&authPage){
      window.location.href = "/todo"


   }

   // 토큰이 없을 때,todo페이지에 접근하려고 하면 로그인 페이지로 이동
   if(!authStorage.getToken()&&todoPage){
      window.alert("로그인이 필요합니다.")

      window.location.href = "/auth/login"
         // navigate("/auth/login")
   }
}

export default useAuth;

진입전에 인증 검사!

그렇다면 언제 인증 검사를 하는 것이 맞을까요? 해당 페이지 진입한 후에 검사하는 것보단 진입하기 전에 검사하는 것이 보안적으로 낫겠죠?

위와 같이 진입전에 인증 검사를 하려면 react-router-domloader 기능을 사용하면 됩니다.

const router = createBrowserRouter([
    {
        path:"/",
        element:<Root/>,
      	loader:async(params) =>{} 

loader 함수는 비동기 함수이며 해당 라우트에 진입전에 라우트에 해당되는 컴포넌트가 로드될 때 실행됩니다.

그래서 위 loader 함수에 로그인 인증 검사 로직을 실행하였어요!

변경된 코드는 다음과 같습니다.

router.ts

import {createBrowserRouter, redirect} from "react-router-dom";
import Login from "../page/login/login.tsx";
import Signup from "../page/signup/signup.tsx";
import Todo from "../page/todo/todo.tsx";
import Root from "../page/root/root.tsx";
import TodoDetails from "../page/todo/details/todoDetails.tsx";
import TodoRegister from "../page/todo/register/todoRegister.tsx";
import {authStorage} from "../helper/auth/authStorage.ts";
import {AuthCheck, authCheck} from "../helper/auth/authCheck.ts";
import {RouteName} from "./routeName.ts";

const router = createBrowserRouter([
    {
        path:"/",
        element:<Root/>,

        children:[
            {
                path: "todo",
                element:<Todo/>,
                loader: AuthCheck.authPageCheck,
                children:[
                    {
                        path: ":id",
                        element:<TodoDetails/>
                    },
                    {
                        path: "register",
                        element:<TodoRegister/>
                    }
                ]
            },
            {
                path:"auth",
                loader: AuthCheck.notAuthPageCheck,
                children:[
                    {
                        path:"login",
                        element:<Login/>,

                    },
                    {
                        path:"signup",
                        element:<Signup/>
                    }
                ]
            }
        ]
    }

]);


export default router;

authCheck.ts

import {authStorage} from "./authStorage.ts";
import {redirect} from "react-router-dom";
import {RouteName} from "../../router/routeName.ts";


/**
 * 로그인 체크
 */

export class AuthCheck{
    static async authPageCheck(){
        if(!authStorage.getToken()){
            window.alert("로그인이 필요합니다.")
            return redirect(RouteName.LOGIN)
        }
        return null
    }

    static async notAuthPageCheck(){
        if(authStorage.getToken()){
            window.alert("이미 로그인이 되어있습니다.")
            return redirect(RouteName.TODO)
        }
        return null
    }


}

그리고 기존에 Root 컴포넌트에서 호출하였던 useAuth 커스텀 훅은 제거해줬어요.
Root.tsx

import useAuth from "../../helper/auth/useAuth.ts";
import Header from "../../layout/header/header.tsx";
import {Outlet} from "react-router-dom";

function Root() {
    // 인증 처리
    // useAuth()



    return (
        <div>
            <Header/>
            <Outlet/>
        </div>
    );
}

export default Root;

위와 같이 router.ts의 loader에서 로그인 인증 검사 함수를 실행하여 해당 페이지에 진입전에 로그인 검사를 해주도록 변경해봤어요.

로그인 인증검사 방식 변경에 대한 효용성

위와 같이 로그인 인증검사를 페이지 진입후에 하는것보다 진입전에 하는것으로 바꿔보았는데요.

두가지 효용성이 있었던 것 같아요.

1. 보안성

페이지에 진입전에 검사를 하기 때문에 인증이 안된 사용자가 무조건 해당 페이지에는 진입할 수 없습니다. 이전에는 일단 한번 진입한 이후에 리다이렉트를 해줬죠. 이는 권한이 없는 사용자가 인증 페이지에서 뭔 짓을 할지 모르니 애초에 못 들어오는 것이 보안적으로 더 좋다고 생각이 들었습니다.

2. 필요할 때만 인증 함수 호출

변경전

변경전 코드를 확인해보면 최상단 컴포넌트인 Root.tsx 컴포넌트에서 useAuth라는 커스텀 훅을 호출하여 어떠한 액션이 일어날 때마다 계속 해당 함수가 호출되었어요.

위 함수가 호출되는 메모리 비용이 많이 들진 않더라도 매번 해당 함수가 호출된다는건 어찌보면 불필요하게 호출된다고 볼 수 있죠.

변경후

하지만 변경이후에는 해당 페이지 진입할 때에만 검사를 하며 호출을 하고 그 이외에는 불필요한 함수를 호출하지 않아도 됩니다.

결론

이전에 React 프로젝트를 진행하면서 권한 체크를 할 때, 항상 페이지 진입후에 해줬었는데요. 이번 기회로 페이지 진입 전에 권한 체크를 하게 되는 방법을 알게 되어 좋은 기회였던 것 같아요.

모든 코드는 다음에서 확인하실 수 있어요.
https://github.com/BrightJun96/wanted-pre-onboarding-challenge-fe-27

profile
FE DEVELOPER

0개의 댓글