Node.js + Express + TypeScript 게시판 만들기 #6 – 회원가입 API 구현 (bcrypt)

Node.js + Express + TypeScript 게시판 만들기 #1 – 개발 환경 구성

Node.js + Express + TypeScript 게시판 만들기 #2 – nodemon 설정과 라우터 분리

Node.js + Express + TypeScript 게시판 만들기 #3 – dotenv 설정과 Controller · Service · Middleware 구조화

Node.js + Express + TypeScript 게시판 만들기 #4 – morgan, helmet, cors로 서버 기본 세팅

Node.js + Express + TypeScript 게시판 만들기 #5 – MariaDB 연결과 DB 환경설정

이전 글에서 MariaDB 연결까지 끝냈다.

이번 글에서 할 것:

  • bcrypt 설치 및 비밀번호 해시 처리
  • Repository 분리로 DB 접근 분리
  • 회원가입 API(/auth/signup) 구현
  • user_id 중복 체크 후 저장

1. bcrypt 설치

>npm i bcrypt
>npm i -D @types/bcrypt

비밀번호는 평문으로 저장하면 안되기 때문에 해시로 변환해야 한다. bcrypt는 그를 위한 라이브러리이다.

2. Repository 만들기 (DB 접근 분리)

src/repository/user_repo.ts 생성

import { pool } from '../config/db';

export const findUserByUserId = async (userId: string) => {
    const [rows] = await pool.query(
        `select
            id
        from
            users
        where
            user_id = ? limit 1`,
        [userId]
    );

    const arr = rows as any[];
    return arr[0] ?? null; // 결과값이 있으면 arr[0] 반환 없으면 null 반환
};

export const createUser = async (data: {
    role_code: string;
    user_id: string;
    password_hash: string;
    name: string;
    phone?: string;
    email?: string;
}) => {
    const { role_code, user_id, password_hash, name, phone, email } = data;
    await pool.query(
        `insert into users (
            role_code,
            user_id,
            password_hash,
            name,
            phone,
            email)
        values (
            ?,
            ?,
            ?,
            ?,
            ?,
            ? )`,
            [role_code, user_id, password_hash, name, phone ?? null, email ?? null]
    );
};

findUserByUserId : user_id 아이디로 가입된 아이디가 있는지 체크한다. (파라미터 userId)

createUser : data에 필요한 데이터를 파라미터로 받는다. (role_code, user_id, password_hash, name, phone, email)

phone ?? null, email ?? null : 마찬가지로 값이 없으면 null을 넣는다.

3. 회원가입 컨트롤러 구현

src/controller/auth_controller.ts 생성

import e, { Request, Response, NextFunction } from 'express';
import bcrypt from 'bcrypt';
import { createUser, findUserByUserId } from '../repository/user_repo';

export const signup = async (req: Request, res: Response, next: NextFunction) => {
    try{
        const { role_code, user_id, password, name, phone, email } = req.body ?? {};

        if (!role_code || !user_id || !password || !name) {
            return res.status(400).json({ message: 'role_code, user_id, password, name required' });
        }

        const exists = await findUserByUserId(user_id);

        if (exists) return res.status(400).json({ message: 'user_id already exists' });

        const password_hash = await bcrypt.hash(password, 10);
        await createUser({ role_code, user_id, password_hash, name, phone, email });
        return res.status(201).json({ message: 'ok' });
    } catch (e) {
        return next(e);
    }
};

– if (!role_code || !user_id || !password || !name) { :

회원가입에 필요한 필수값 체크를 하고 없으면 400 에러로 간다.

어차피 화면에서 또 막을 예정이긴 하다.

– const exists = await findUserByUserId(user_id); :

이미 있는 계정이면 마찬가지로 400 return한다.

– const password_hash = await bcrypt.hash(password, 10);

bcrypt로 비밀번호를 해싱한다.

– await createUser({ role_code, user_id, password_hash, name, phone, email });

user_repo의 createUser로 계정을 생성한다.

4. 라우터 연결

src/routes/index_routes.ts 수정

import { Router } from 'express';
import { signup } from '../controller/auth_controller';

const router = Router();

router.post('/auth/signup', signup);

export default router;

/auth/signup 으로 요청이 들어오면 auth_controller의 signup을 호출한다.

아직 front가 없으므로 postman으로 body에 데이터를 담아 요청을 보낸다.

http://localhost:3000/auth/signup

Body

{ “role_code”: “0000”, “user_id”: “admin”, “password”: “1234”, “name”: “관리자”}

ok응답을 받으면서 정상적으로 회원가입이 된 것을 확인할 수 있다.

다음 글 예고: 로그인 API 구현

댓글 남기기