본문 바로가기

Learn/Next.js

Next.js (8) JWT 회원가입 기능

 

Next-auth 라이브러리를 사용하면 기본적으로 모든 방식이 JWT

유저 세션데이터를 DB에 저장해두지 않고 JWT만 유저에게 보내고

유저가 로그인이 필요한 페이지 방문시 유저가 제출한 JWT만 검사해서 입장시켜주는 방식

 

JWT를 사용하면 로그인 구현은 쉬워지는데

JWT방식의 단점같은게 마음에 안들어서 

session 방식으로 회원기능을 만들고 싶으면 DB adapter 기능을 쓰면 된다.

 

DB adapter 기능을 켜놓으면 

1. 첫 로그인시 자동으로 유저를 회원가입 시켜서 DB에 유저 회원정보를 보관

2. 로그인시 자동으로 유저가 언제 로그인했는지 세션정보를 DB에 보관

3. 서버에서 지금 로그인된 유저정보가 필요하면 JWT가 아니라 DB에 있던 세션정보를 조회해서 가져온다. 

4. 로그아웃시 유저 세션정보는 DB에서 삭제. 

 

그래서 가입된 유저정보를 DB에 저장하는게 필요하거나

유저 로그인상태를 엄격하게 관리하고 싶으면 DB adapter 기능을 사용

 

MongoDB adapter 설정

 

npm install @next-auth/mongodb-adapter

redis같은 것들 쓰면 데이터 저장시 하드말고 램을 사용하기 때문에 빨라서 session 방식 구현할 때 인기

 

auth/[...nextauth].js에 추가

import { MongoDBAdapter } from "@next-auth/mongodb-adapter";
 adapter: MongoDBAdapter(connectDB),

 session 방식으로 회원기능 만들기 끝

 

sessions에는 현재 로그인된 유저 정보가 들어있습니다. 로그인 유효기간도 적혀있음

users는 유저들 보관하는 곳입니다. 유저끼리 구분은 이메일로 합니다. 

accounts는 유저계정 보관하는 곳입니다. 

하나의 유저는 여러개의 계정을 가지고 있을 수 있기 때문에 여러 계정마다 이메일이 중복될 수도 있습니다. 

 

Q. users vs accounts 차이가 뭐임? 

어떤 1명의 유저가 내 사이트에 Github으로도 가입하고 Google로도 가입을 해버린 경우를 가정해봅시다.

근데 이 사람의 

Github 계정은 test@naver.com

Google 계정도 test@naver.com 으로 되어있는 겁니다.

 

이 경우 users 컬렉션엔

test@naver.com 이메일을 가진 document 1개만 생성

 

accounts 컬렉션엔

1. test@naver.com + Github이 써있는 document 

2. test@naver.com + Google이 써있는 document 

이렇게 2개가 생성됩니다. 

이런 식으로 유저는 1명이지만 계정은 2개 이상 생성이 가능

(이메일이 같으면 같은 유저라고 자동으로 간주합니다)

 

 

 

(참고) DB adapter 사용시 기본으로 설정되어있는 database에 accounts, sessions, users 3개 컬렉션들을 생성할텐데

그래서 forum database에 저런 컬렉션들이 생성

그게 싫고 다른 이름의 database에 넣고 싶으면 

MongoDB 접속 URL에 물음표가 있을텐데 그거 왼쪽에 원하는 database 이름을 넣으면 됩니다

 

아이디/비번 방식으로 로그인

 

Next-auth 라이브러리 설정에서 Credentials provider를 선택하면 됩니다.

다만 이 경우 session 방식 말고 강제로 JWT 방식만 사용하도록 셋팅

 

app/register/page.js

export default function Register() {
    return (
    <div>
        <form method="POST" action="/api/auth/signup">
            <input name="name" type="text" placeholder="이름" />
            <input name="email" type="text" placeholder="이메일" />
            <input name="password" type="password" placeholder="비번" />
            <button type="submit">id/pw 가입요청</button>
        </form>
    </div>
    )
}

 

회원가입 페이지 만들고

 

비밀번호 암호화 라이브러리 bcrypt 설치

https://www.npmjs.com/package/bcrypt

 

bcrypt

A bcrypt library for NodeJS.. Latest version: 5.1.0, last published: 9 months ago. Start using bcrypt in your project by running `npm i bcrypt`. There are 3999 other projects in the npm registry using bcrypt.

www.npmjs.com

npm install bcrypt

 

회원가입 서버 만들고

import { connectDB } from "@/util/database";
import bcrypt from 'bcrypt'

export default async function handler(res,req){
    if(res.method === 'POST'){
        let hash = await bcrypt.hash(res.body.password,10)
        res.body.password = hash
       
       

        let db = (await connectDB).db('forum');
        await db.collection('user_cred').insertOne(res.body);
        req.status(200).json('가입성공')
    }
}

 

import { connectDB } from "@/util/database";
import { MongoDBAdapter } from "@next-auth/mongodb-adapter";
import NextAuth from "next-auth";
import GithubProvider from "next-auth/providers/github";
import CredentialsProvider from "next-auth/providers/credentials";
import bcrypt from 'bcrypt';

export const authOptions = {
  providers: [
    GithubProvider({
      clientId: 'Github에서 발급받은 ID',
      clientSecret: 'Github에서 발급받은 Secret',
    }),

    CredentialsProvider({
      //1. 로그인페이지 폼 자동생성해주는 코드
      name: "credentials",
        credentials: {
          email: { label: "email", type: "text" },
          password: { label: "password", type: "password" },
      },

      //2. 로그인요청시 실행되는코드
      //직접 DB에서 아이디,비번 비교하고
      //아이디,비번 맞으면 return 결과, 틀리면 return null 해야함
      async authorize(credentials) {
        let db = (await connectDB).db('forum');
        let user = await db.collection('user_cred').findOne({email : credentials.email})
        if (!user) {
          console.log('해당 이메일은 없음');
          return null
        }
        const pwcheck = await bcrypt.compare(credentials.password, user.password);
        if (!pwcheck) {
          console.log('비번틀림');
          return null
        }
        return user
      }
    })
  ],

  //3. jwt 써놔야 잘됩니다 + jwt 만료일설정
  session: {
    strategy: 'jwt',
    maxAge: 30 * 24 * 60 * 60 //30일
  },


  callbacks: {
    //4. jwt 만들 때 실행되는 코드
    //user변수는 DB의 유저정보담겨있고 token.user에 뭐 저장하면 jwt에 들어갑니다.
    jwt: async ({ token, user }) => {
      if (user) {
        token.user = {};
        token.user.name = user.name
        token.user.email = user.email
      }
      return token;
    },
    //5. 유저 세션이 조회될 때 마다 실행되는 코드
    session: async ({ session, token }) => {
      session.user = token.user;  
      return session;
    },
  },

  adapter: MongoDBAdapter(connectDB),
  secret: 'qwer1234'  
};
export default NextAuth(authOptions);

 

이렇게 마무리!

'Learn > Next.js' 카테고리의 다른 글

Next.js로 포트폴리오 만들기[Vercel]  (0) 2023.07.18
Next.js (7) 로그인 방식 정리 및 OAuth 기능 구현  (0) 2023.07.09
Next.js (6) static/dynamic rendering/캐싱  (0) 2023.07.08
Next.js (5)  (0) 2023.07.07
Next.js 프로젝트(4)  (0) 2023.07.05