7. 회원가입, 로그인(Credentials provider + JWT 사용하기)

윤지영·2024년 3월 29일

1. 회원가입 페이지

  • 비밀번호 암호화해서 저장하기 위한 bcrypt 라이브러리 설치
npm install bcrypt
  • 회원가입 페이지 생성 및 코드 작성
    src/app/register/page.js

  • api 작성
    src/app/api/auth/signup/route.js

  • await bcrypt.hash(data.password, 10);
    비밀번호 해싱 후 기존 password 대신 해싱된 password 데이터 덮어쓴 후 db에 추가해주기!

import { connectToDatabase } from "@/utils/database";
import { NextResponse } from "next/server";
import bcrypt from "bcrypt";

export async function POST(req) {
  const { collection } = await connectToDatabase("user_cred");

  try {
    const data = await req.json();
    const hashedPassword = await bcrypt.hash(data.password, 10); // 비밀번호 해싱
    const userData = {
      ...data,
      password: hashedPassword, // 'password' 필드를 해시된 값으로 덮어씀
    };
    await collection.insertOne(userData);
    return NextResponse.json({ message: "사용자 등록 성공" }); // 응답 메시지 반환
  } catch (error) {
    console.error(error);
    return NextResponse.json(
      { error: "서버 오류가 발생했습니다." },
      { status: 500 }
    );
  }
}

2. id/password 로그인 페이지

Credentials provider 설정하기

// 기존 코드 생략
import CredentialsProvider from "next-auth/providers/credentials";
import bcrypt from "bcrypt";

const authOptions = {
  providers: [
    GithubProvider({
    // ...
    }),
   // 기존 코드 생략

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

      //2. 로그인요청시 실행되는코드
      //직접 DB에서 아이디,비번 비교하고
      //아이디,비번 맞으면 return 결과, 틀리면 return null 해야함
      async authorize(credentials) {
        const db = (await connectDB).db("board");
        const 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;
    },
  },

  secret: process.env.NEXTAUTH_SECRET, //jwt생성시쓰는암호
  adapter: MongoDBAdapter(connectDB),
};

const handler = NextAuth(authOptions);

export { handler as GET, handler as POST, authOptions };

3. TODO

  • 회원 가입 시 admin 계정, 일반 유저 구분해주기
    role:admin/nomal

  • 유효성 검사

    • input 빈 값 체크
    • email 중복체크
    • 비밀번호 유효성
profile
쑥쑥쑥쑥 레벨업🌱🌼🌳

0개의 댓글