키모스토리

#4. register (MongoDB, Jose, session, cookie) 본문

Web Devlopment/Next-Blog Project

#4. register (MongoDB, Jose, session, cookie)

키모형 2025. 4. 4. 17:52
반응형

https://www.mongodb.com/

 

MongoDB: The World’s Leading Modern Database

Get your ideas to market faster with a flexible, AI-ready database. MongoDB makes working with data easy.

www.mongodb.com

 

1. 인스톨

npm install mongodb

 

2. connecton string setup

mongodb+srv://user_id:<db_password>@cluster0.y42buoh.mongodb.net/?retryWrites=true&w=majority&appName=Cluster0

 

root / .env.local 파일 작성

// db-id, db-password : 몽고디비에 설정된 실재 id, pwd 입력
DB_URI = "mongodb+srv://[db-id]:[db-password]@cluster0.y42buoh.mongodb.net/?retryWrites=true&w=majority&appName=Cluster0"

 

/src/lib/db.js 작성 (몽고디비 연결 및 db작업 정의)

// lib/db.js

const { MongoClient, ServerApiVersion } = require("mongodb");

// 환경설정 파일 (.env.local) 에서 DB_URI를 가져옵니다.
if(!process.env.DB_URI) {
  throw new Error("DB_URI is not set");   
}

// MongoDB 클라이언트를 생성합니다.
const client = new MongoClient(process.env.DB_URI, {
  serverApi: {
    version: ServerApiVersion.v1,
    strict: true,
    deprecationErrors: true,
  },
});


// DB에 연결하는 함수입니다.
async function getDB(dbName) {
  try {
    // Connect the client to the server	
    await client.connect();
    console.log(">>>> Connected to MongoDB <<<<");
    return client.db(dbName);
  } catch (err) {
    console.error(err);
  } 
}

// DB에 연결된 후, collection을 가져오는 함수입니다.
// DBNAME은 next_blog_db 입니다.
export async function getCollection(collectionName) {
  const db = await getDB('next_blog_db');
  if(db) {
    // console.log(db.collection(collectionName));
    return db.collection(collectionName);
  }
  return null;
}

 

Password Hash

npm i bcrypt

 

문자열을 bcrypt를 이용하여 해시값으로 변경

  // Hash the password before saving it to the database.
  // 비밀번호를 해시하여 DB에 저장합니다.
  const hashedPassword = await bcrypt.hash(password, 10);

  // users collection에 회원가입 정보를 저장합니다.
  // mongodb collection에 신규 정보 등록 (비번은 해시값으로)
  const result= await userCollection.insertOne({    
    name,
    email,
    password: hashedPassword,
  });

 

 

Session, Cookie 정보를 JWT로 생성, 이용

Jose

npm i jose 

 

Secretkey 생성 방법

1. OpenSSL 설치

Windows에 OpenSSL을 설치하는 방법:

설치할 때 “The OpenSSL binaries/libraries will be copied to the Windows system directory” 옵션을 체크 해제하고, 사용자 디렉토리에 설치하세요.

2. 환경 변수 등록

설치 후 OpenSSL의 설치 경로(예: C:\Program Files\OpenSSL-Win64\bin)를 시스템 환경 변수 PATH에 추가해야 합니다.

방법:

  1. Win 키 + 검색 → "환경 변수" 입력 → 시스템 환경 변수 편집 클릭
  2. "환경 변수(N)..." 버튼 클릭
  3. "시스템 변수"에서 Path 선택 후 편집
  4. OpenSSL의 bin 폴더 경로 추가 예: C:\Program Files\OpenSSL-Win64\bin
  5. 확인 → 확인 → PowerShell 새로 열기

3. 테스트

PowerShell을 다시 열고 아래 명령을 입력해 확인:

openssl version

버전 정보가 출력되면 성공입니다.

 

그 다음 아래 명령 실행 가능:

openssl rand -base64 32

 

 

 

회원가입 처리

src/actions/auth.js

"use server";

import bcrypt from "bcrypt";
import { getCollection } from "@/lib/db";
import { RegisterFormSchema } from "@/lib/rules";
import { redirect } from "next/navigation";
import { createSession } from "@/lib/session";

export async function register(state, formData) {
  // await new Promise((resolve) => setTimeout(resolve, 3000));

  // 회원가입 요청으로 넘어온 formData를 사용하여 유효성 검사를 수행합니다.
  // 유효성 검사 규칙은 src/lib/rules.js에 정의되어 있습니다.
  const validatedFields = RegisterFormSchema.safeParse({
    name: formData.get("name"),
    email: formData.get("email"),
    password: formData.get("password"),
    confirmPassword: formData.get("confirmPassword"),
  });

  // 유효성 검사에 실패한 경우, 에러 메시지를 반환합니다.
  // 에러 메시지는 src/lib/rules.js에 정의된 규칙에 따라 다르게 표시됩니다.
  if (!validatedFields.success) {
    return {
      errors: validatedFields.error.flatten().fieldErrors,
      name: formData.get("name"),
      email: formData.get("email"),
    };
  }

  // 유효성 검사 통과 후 DB에 회원가입 정보를 저장합니다.
  const {name, email, password} = validatedFields.data;  
  // console.log(name, email, password);

  // next_blog_db DB에서 users collection(테이블)을 가져옵니다.
  const userCollection = await getCollection("users");
  
  // users collection이 존재하지 않는 경우, 에러 메시지를 반환합니다.
  if( !userCollection) {
    return { 
      errors: validatedFields.error.flatten().fieldErrors,
      name: formData.get("name"),
      email: formData.get("email"),
    };
  }

  // user email이 이미 존재하는 경우, 에러 메시지를 반환합니다.
  const exitingUser = await userCollection.findOne({ email });
  if (exitingUser) {
    return {
      errors: { email: "Email already exists." },
      name: formData.get("name"),
    };
  }

  // Hash the password before saving it to the database.
  // 비밀번호를 해시하여 DB에 저장합니다.
  const hashedPassword = await bcrypt.hash(password, 10);

  // users collection에 회원가입 정보를 저장합니다.
  const result= await userCollection.insertOne({    
    name,
    email,
    password: hashedPassword,
  });

  // console.log(result.insertedId);

  // Create Session
  await createSession(result.insertedId.toString());  
  
  // Rediect to login page after successful registration.
  redirect("/dashboard");
}

 

회원가입이 정상 처리된 후 세션생성 단계 진행 => /lib/session.js 에 세션관련 코드 정의 (jose, jwt, cookie)

  // Create Session
  await createSession(result.insertedId.toString());

 

 

/lib/session.js

import { cookies } from "next/headers";
import { jwtVerify, SignJWT } from "jose";

// 환경설정 파일에서 SESSION_SECRET을 가져옵니다.
const secretKey = process.env.SESSION_SECRET;
const encodeKey = new TextEncoder().encode(secretKey);

// 세션을 암호화하는 함수입니다.
// payload는 세션에 저장할 데이터입니다.
// 이 함수는 JWT를 생성하여 세션을 암호화합니다.
// JWT는 JSON Web Token의 약자로, JSON 객체를 사용하여 정보를 안전하게 전송하는 방법입니다.
export async function encrypt(payload){
  return new SignJWT(payload)
    .setProtectedHeader({ alg: "HS256" })
    .setIssuedAt()
    .setExpirationTime("6h")
    .sign(encodeKey);
};

// 세션을 복호화하는 함수입니다.
// session은 암호화된 세션 데이터입니다.
export async function decrypt(session) {
  try {
    const { payload } = await jwtVerify(session, encodeKey, {
      algorithms: ["HS256"],
    });
    return payload;
  } catch (error) {
    console.error("Failed to vrefy session", error);
  }
}

// 세션을 생성하는 함수입니다.
// userId는 세션에 저장할 사용자 ID입니다.
export async function createSession(userId) {
  const expireAt = new Date(Date.now() + 6 * 60 * 60 * 1000); // 6시간 후 만료
  const session = await encrypt({ userId, expireAt });
  const cookieStore = await cookies();
  
  cookieStore.set("session", session, {
    httpOnly: true,
    secure: true,
    expires: expireAt,
    sameSite: "lax",
    path: "/",
  }); 
}

 

가입 완료, dashboard 로 이동 완료, application -> cookies 정보에 쿠키값 확인 

반응형

'Web Devlopment > Next-Blog Project' 카테고리의 다른 글

#6. Active Links  (0) 2025.04.05
#5. server-only  (0) 2025.04.05
#3. zod.dev (validation)  (0) 2025.04.04
#2. useActionState  (0) 2025.04.04
#1. Setup  (0) 2025.04.03