본문 바로가기
  • 삽질하는 자의 블로그
메인-프로젝트/Next.js - 오늘 뭐먹지? 프로젝트

6. 로그인 기능 구현 with Next-Auth

by 이게뭐당가 2022. 12. 2.

로그인 기능은, 뭐먹지? 페이지에 반드시 필요한 기능이었습니다.

우선, 수많은 음식들 중, 내가 원하는 음식은 고작 수십가지! 회원 별로, 서로 다른 음식들을 "찜" 할 수 있어야 했습니다.

 

Express 를 사용했을 때에는, connect-mongodb-session 패키지를 사용하여,  DB 에, 유저의 정보를 저장, 

 

로그인의 기능이 정상적으로 활용 되었을때, 유저들에게 auth 한 session 을 만들어주고, 클라이언트 사이드의 쿠키에 저장을 하여, 쿠키가 만료 될때까지, 자유로운 이동을 하게 하였다.

 

Nextjs 에서는 JWT 를 이용하여, 로그인 한 유저에게, Json Web Token 을 발급한다.

토큰은, "서버에서 생성" 되며, 클라이언트에게 전달되고, 유저는 클라이언트 사이드 브라우저, 즉 , 쿠키에 저장한다.

 

클라이언트(유저)는 요청을 보낼때, 자동으로 토큰을 첨부하여 요청하며

 

서버에서 validation 을 통해, 요청을 수용하거나 거절한다.

 

그렇다면 JWT 를 구현해보자

next-auth 를 사용하여, 로그인 기능을 구현해봅니다.

next-auth DOCS : https://next-auth.js.org/getting-started/example

 

NEXT-AUTH 는, nextjs 에 "아주아주 특화되어 있는"  기가 막힌 Authentication 서비스이다.

 

 

 

최신버젼은 V4 이다. 기왕 하는거 최신버젼 써봐야 하지 않겠는가?

DOCS 에 들어가서 하란대로 해보자.

 

1. npm (node package manager) 를 사용해 install한다.

2. api 폴더에, auth 폴더를 만들어, [...nextauth].js 를 생성해, Provider 를 생성한다.

3. useSession 을 사용하기 위해, SessionProvider 를 생성해, 전체 애플리케이션을 감싸준다.

 

4. 그렇다면 이제, 클라이언트 사이드에서는 useSession 을 통해, Auth 를 부여받은 유저의 정보를 알 수 있다.

5. API 보호를 위해(아무나 API 에 접근하지 못하게) unstable_getServerSession() 을 사용하여, API 를 보호한다.

 

자 준비는 끝났다. 따라해볼까?

 

1번은 다 할 수 있으니

2번부터 가보자!

 

우선, 가벼운 웹사이트를 위해,  "회원가입 연동" OAtuh 보다는

"Credentials" Provider 를 이용하여, "스스로 짠 로직으로 토큰을 발급할 것이다."

 

 

https://next-auth.js.org/providers/credentials

 

Credentials | NextAuth.js

Overview

next-auth.js.org

 

 

authOptions 에는 여러가지 "옵션" 을 선택 할 수 있다.

 

가장 대표적으로는, session, providers, secret 이 있다. (필수기 때문에)

 

1. providers 옵션 안에, 배열을 만들어, "우리가 사용할 Provider" 를 넣는다. 

 

2. Provider 안에, 메서드로, authroize 를 넣어, " Auth 로직을 만든다".

   이 로직이 정상적으로 끝에 도달한다면,  return 을 통해, Auth 할 유저의 정보를 반환할 것이다.

 

3. secret 옵션을 통해, 원하는 secret 이름을 넣는다(아무거나)

https://next-auth.js.org/configuration/options#secret

 

Options | NextAuth.js

Environment Variables

next-auth.js.org

4. session 옵션을 통해, 원하는 형태의 인증 토큰 종류를 넣는다. 

https://next-auth.js.org/adapters/dgraph#working-with-jwt-session-and-auth-directive

 

Dgraph | NextAuth.js

This is the Dgraph Adapter for next-auth.

next-auth.js.org

5. authorize 의 credential 매개변수 안 에는, "로그인 할때, argument가 들어간다"

 

6. retrun 할 수 있는 값은 id, email, name 세가지가 전부이다.

 

< pages / api / auth / [...nextauth].js >

import NextAuth from "next-auth";
import CredentialsProvider from "next-auth/providers/credentials";
import { findUserInfo, connectDb } from "../../../helper/db-util";
import bcrypt from "bcrypt";

export const authOptions = {
  session: {
    strategy: "jwt",
  },
  providers: [
    CredentialsProvider({
      async authorize(credentials) {
        const client = connectDb();

        const userInfo = await findUserInfo(client, credentials.email);

        if (!userInfo) {
          throw new Error("정보를 확인하세요");
        }

        const passwordValidation = await bcrypt.compare(
          credentials.password,
          userInfo.password
        );

        if (!passwordValidation) {
          throw new Error("비밀번호를 확인하세요");
        }

        return {
          email: credentials.email,
          name: userInfo.name,
        };
      },
    }),
  ],
  secret: process.env.SECRET,
};
export default NextAuth(authOptions);

3. SessionProvider 는 그대로 똑같이 따라하고

 

4. 로그인을 해보자

 

https://next-auth.js.org/getting-started/client#signin

 

Client API | NextAuth.js

The NextAuth.js client library makes it easy to interact with sessions from React applications.

next-auth.js.org

로그인 폼에,  signIn () 메서드 한방이면 로그인 이 가능하다! 우와!

 

signIn 메서드 안에, redirect (로그인 후 강제이동 옵션) 을 false 로 설정하면, 메서드는, 프로미스를 반환한다.

메서드 의 첫번째 파라미터에는,  사용한 Provider 이름을 넣어준다.

두번째 파라미터에는, 인증에 필요한 값을 넣어준다.

 

  async function submitHandler(e) {
    e.preventDefault();

    const result = await signIn("credentials", {
      redirect: false,
      email: emailRef.current.value,
      password: passwordRef.current.value,
    });

    if (status === "unauthenticated") {
      setMessage(result.error);
    }
    if (result.error == null) {
      router.replace("/");
    }
  }

로그인 폼의 input 태그에, ref를 붙여주고, 버튼을 누르면, SignIn 하게 만든다.

 

signIn 메서드는, email 과 password 를 Provider 의 Credentails 파라미터의 인수로 넣어,

인증조건에 부합하는지 확인한다.

 

5. 로그인에 성공했다!, useSession을 이용하여, 로그인된 유저의 정보를 받자.

 

function RandomSelectComponent(props) {
  const { data: session, status } = useSession();

   console.log(session)
   console.log(status)
 
session 안에는, Provider 에서 반환한 유저의 정보가 들어가고,
status 는,  loading, authenticated, unauthenticated 로 분류된다.

잊지 말아야 할 것은  useSession 은 클라이언트 사이드 에서만 사용 가능하다는 것이다.

getStaticProps, getServerSideProps, API 등, 서버측 코드에는 사용 불가능하다.

 

이제 우리는 useSession 을 통해

1. 동적인 코드를 생성하고

2. 로그인 한 유저에 따라, 다른 데이터를 fetch 할 수 있다

댓글