Next.js에서 특정 페이지에 인증 (로그인 체크)을 작성할 수있는 간단한 방법

next.js에서 특정 페이지에 인증을 작성하는 방법에 대한 메모.
인증을 실시하는 Auth 컴퍼넌트를 작성해, 그것으로 둘러싸면 인증이 걸리는 방법의 체크.

NextAuth라든지의 라이브러리도 있습니다만, 일단, 「소의 실장 방법」을 확인해 두고 싶다.

하고 싶은 일



아래와 같은 흐름을 만들고 싶다.



준비



검증을 위한 프로젝트 차이 k-말이.
npx create-next-app next-auth-test
cd next-auth-test

이번은 인증의 방식(로그인의 유지)으로서 쿠키에 인증 정보를 기입해 그것이 있는지, 없는지로 로그인 상태를 판단하는 구현으로 하고 싶습니다.

react-cookie라고 라이브러리도 시도했지만, 미사용의 변수나 함수를 정의할 필요가 있고 warning이 우자이므로 js-cookie를 이용합니다.
npm install js-cookie

인증을 실시하는 Auth 컴퍼넌트를 기술하는 auth.js 를 components 이하에 작성.
mkdir components
touch components/auth.js

인증 화면을 담당하는 login.js와 인증 대상이되는 private.js를 작성.
touch pages/login.js pages/private.js

구현



그럼 구현해 갑니다.

auth.js



쿠키의 유무를 체크하고 있으면 그대로, 없으면 login에 리디렉션 시킬 뿐.
Cookie 체크 로직을 여러가지 방식으로 바꾸면 여러가지 응용은 할 수 있는 상정.

쿠키에 쓰는 정보를 인증 쿠키라고 모르는 이름이 좋고, 안이하게 생성할 수 없는 값이 좋고, 가능하면 서버측에서 httpOnly로 처리하는 편이 좋습니다(클라이언트 측에서 signedIn=true등은 곧바로 기입할 수 있으므로 좋지 않다).

children을 props로 받아서 return하면 아이 컴퍼넌트의 렌더링에 진행한다.

components/auth.js
import { useRouter } from "next/router";
import Cookies from "js-cookie";

const Auth = ({ children }) => {

    //router
    const router = useRouter();

    //Cookieのチェック(これをいろいろ認証タイプにより変更)
    const signedIn = Cookies.get("signedIn");
    //signedInがtrueじゃなければ/loginへ
    if (signedIn !== "true") router.replace("/login");

    //何もなければ次へ(そのまま処理)
    return children;
}

export default Auth;

login.js



간이 로그인 화면을 작성.
여기에서는 로그인 버튼 누르면 무조건 로그인 버립니다만, 여기서 ID, Password 인증 등을 실시하면 좋을 것입니다.

login.js
import Link from "next/link";
import { useRouter } from "next/router";
import Cookies from "js-cookie";

const Login = () => {

    const router = useRouter();

    //ログイン処理(CookieにsignedIn=trueとする)
    const login = () => {
        Cookies.set("signedIn", "true");
        router.replace("/private");
    }

    return (
        <>
            <h1>Login</h1>
            <button onClick={login}>ログイン</button>
            <div>
                <Link href="/"><a>Homeへ</a></Link>
            </div>
        </>
    );
}

export default Login;

index.js



Home 페이지./private에 링크를 붙이고 있을 뿐.

index.js
import Link from "next/link";

const Home = () => {
  return (
    <>
      <h1>Home</h1>
      <div>
        <Link href="/private"><a>Privateへ</a></Link>
      </div>
    </>
  );
}

export default Home;

private.js



Auth 태그로 둘러싸고 액세스 시 인증 상태인지 확인합니다.
OK라면 그대로 표시, NG이면/login로 리디렉션.
로그아웃은 단지 쿠키를 지우고 있을 뿐.

private.js
import Link from "next/link";
import { useRouter } from "next/router";
import Cookies from "js-cookie";

//認証コンポーネント読み込み
import Auth from "../components/auth";

const Private = () => {

    const router = useRouter();

    //ログアウト処理
    const logout = () => {
        Cookies.remove("signedIn");
        router.replace("/login");
    }

    return (
        <Auth>
            <h1>Private</h1>
            <button onClick={logout}>ログアウト</button>
            <div>
                <Link href="/"><a>Homeへ</a></Link>
            </div>
        </Auth>
    );
}

export default Private;

react-router-dom에 의한 라우팅이 인증에 있어서는 알기 쉬울까. . .



쿠키의 가장



여기에서는 signedIn=true이면 로그인 상태로 했습니다. 하지만 이 상태는 사용자나 XXS 취약성이 있으면 즉시 위조할 수 있습니다. 가장 쉬운 방법은 브라우저 개발자 도구 콘솔에서 JS를 실행하는 것입니다.

아래와 같이 콘솔에서,
document.cookie="signedIn=true"

로 로그인 상태로 할 수 있습니다.



안전책으로는
  • 어쨌든 자격 증명을 모르는 정보입니다.
  • 안이하게 생성할 수 없고, 유저 의존 정보로 한다(부정이 발생해도 최악, 개인 단위)
  • SPA라면 token 정보를 취득하기 때문에 일단 그것을 이용하는 등

  • 서버 측 관리
  • httpOnly에서 서버 측에서 쿠키 생성 및 삭제하기

  • 그런가요?

    좋은 웹페이지 즐겨찾기