Node.js 랜덤채팅 프로젝트(2) - 회원가입 구현

2un_seong·2021년 10월 14일
3
post-thumbnail

Step 0

지난 포스팅에서 웹서버를 구동해 보았다.
오늘은 랜덤채팅 사이트를 위한 회원가입을 구현해보자.

Mysql을 이용해 node.js를 db에 연결하고 들어오는 비밀번호를 해시를 이용해 암호화 한 뒤 db에 저장해보고자 한다.



Step1

우선 필요한 모듈을 다운받자

npm i bcryptjs dotenv mysql mysql2 --save

다운 받은 모듈을 하나씩 설명하자면

  • bcryptjs : 비밀번호 암호화
  • dotenv : 보안이 필요한 값들을 안전하게 사용하기위해
  • mysql : 유저 DB 저장
  • mysql2 : mysql promise 사용을 위해


Step2 - DB설정

그 다음 사용자 정보 저장을 위해 DB를 설정하자

지금 만들고자하는 프로젝트인 랜덤채팅에 저장할 데이터가 유저정보, 채팅메세지 정도 이므로 Mysql을 사용하였다.

node.js에서 mysql을 사용하기 위해선 Sequelize를 사용할 수도 있지만 이 프로젝트에선 Mysql 연습을 위해 로컬에 DB와 테이블을 생성후 node.js와 연동 후 쿼리를 보내주는 방식으로 진행했다.

터미널로 Mysql 접속

Mysql 설치는 검색을 통해..

mysql -uroot -p

database 생성 후 선택

create database randchat_db;
use randchat_db;

Users 테이블 생성하기

create table Users(
   id int primary key auto_increment not null,
   email varchar(50) not null unique,
   nickname varchar(30) not null unique,
   gender varchar(5) not null,
   password varchar(100) not null,
   introduce text,
   created_at timestamp not null default current_timestamp,
   updated_at timestamp not null default current_timestamp on update current_timestamp
   );

유저 테이블이 생성이 되었다.
아래의 명령어를 통해 유저 테이블을 확인해보자.

desc Users; 

각 컬럼의 용도에 대해 설명하자면
- email : 로그인id, 유저 인증∙인가용
- nickname : 채팅상에 보여지는 이름
- gender : 원하는 성별 매칭(bool타입이 아니라 string으로 설정한 이유는 나중에 다룰예정)
- password : 비밀번호
- introduce : 채팅상에 보여지는 자기소개
- created_at : 유저 생성 시각
- updated_at : 유저 수정 시각

config/db.js 생성

module.exports = {
 host: process.env.DB_HOST,
 user: process.env.DB_USER,
 database: process.env.DB,
 password: process.env.DB_PWD,
};

이것도 간단하게 설명하자면
- host : 사용하는 DB 서버의 아이피
- user : DB 유저명
- database : 사용할 database명
- password : DB 유저 비밀번호 (처음에는 비밀번호 없음)

json파일로 생성해도 되지만 .env를 사용하기위해 js파일로 생성했다.

.env 생성

.env는 git에 push 할 때 비밀번호와 같은 보안이 필요한 값들이 유출되지 않게 하기 위해 사용한다.

DB=randchat_db
DB_USER=root
DB_PWD=
DB_HOST=localhost
DB_PORT=3000

middleware/pool.js 생성

const mysql = require("mysql2/promise");
const dbsecret = require("../config/db.js"); //github에 올릴 때 비밀번호가 유출되지 않게 하기 위해

const pool = mysql.createPool(dbsecret);
module.exports = pool;



Step3 - 라우터 설정

app.js 수정하기

const express = require('express');
const app = express();
require("dotenv").config();

const authRouter = require('./routes/auth');

// Middlewares
app.use(express.json());
app.use(express.urlencoded({extended: true}));

// API
app.use('/api/auth', authRouter);

// Server
const port = process.env.PORT || 3000

app.get('/', (req, res) => res.send('Welcome to randchat project!'));
app.listen(port, () => console.log(`Server running on port ${port}`));

authenticate를 담당할 라우터를 설정하고 .env파일을 사용할 수 있게끔 했다.

routes/auth.js 생성

const express = require('express');
const router = express.Router();

// 인증
const bcrypt = require('bcryptjs');

// DB
const pool = require('../middleware/pool');

router.post('/signup', async (req, res) => {
    let con1 = await pool.getConnection(async (conn) => conn);

    try { // DB에 email, nickname이 겹치는 user가 있는지 확인
        const same_email = await pool.query(
            "SELECT * FROM Users WHERE email = ?",
            req.body.email
        );
        const same_nick = await pool.query(
            "SELECT * FROM Users WHERE nickname = ?",
            req.body.nickname
        );
        if (same_email[0][0] !== undefined || same_nick[0][0] !== undefined) {
            return res.status(400).json({
                result: false,
                msg: "User is aleady exist!",
            });
        }
    } catch (e) {
        throw e;
    }
    bcrypt.hash(req.body.password, 10, async (err, hash) => {
        if (err) {
            throw err;
        } else {
            try {
                con1.beginTransaction();
                await con1.query(
                    "INSERT INTO Users(email, nickname, gender, password) VALUES(?, ?, ?, ?)",
                    [req.body.email, req.body.nickname, req.body.gender, hash]
                );
                con1.commit();
                res.status(200).json({ result: true, msg: "Success" });
            } catch (e) {
                con1.rollback();
                throw e;
            } finally {
                con1.release();
            }
        }
    });
});
module.exports = router;

이 프로젝트에서는 일관성있는 데이터 관리를 위해 트랜잭션을 사용했다.

req.body로는 email, nickname, gender, password 가 오기로 했다.

위의 코드를 설명하자면

  1. /api/auth/signup [post]로 request가 들어오면 email과 nickname이 겹치는 user가 있는지 확인 (겹치는 user가 있다면 상태코드 400과 json return)

  2. 겹치는 user가 없다면 bcrypt.hash 함수를 통해 password를 암호화 한다.

  3. 암호화가 성공했다면 Users 테이블에 email, nickname, gender, hash(암호화된 비밀번호)를 저장

  4. 상태코드 200과 함께 json return


테스트

postman으로 잘 동작하는지 확인해보자
postman사용법도 검색을 통해..

node app.js

서버를 실행시키고
localhost:3000/api/auth/signup [post]로
email, nickname, gender, password를 담아 전송하자.

"Success"라는 메세지를 받을 수 있다.
혹시 유저가 중첩되서 만들어지진 않을까하여 이 상태 그대로 Send를 보내본다.

"User is already exist!"라는 메세지를 받았다.

이로써 랜덤채팅 프로젝트의 회원가입 기능을 구현하였다.
다음에는 로그인 기능을 구현해보자.

본 포스팅에서 잘못된 정보가 있을 경우 댓글로 알려주시면 감사하겠습니다.

profile
목적을 위해 세운 목표를 향해

3개의 댓글

comment-user-thumbnail
2021년 10월 15일

vscode 에 Thunder Client 익스텐션 좋아요!! 포스트맨 대신에 사용해도 좋을 것 같습니다 ^~^

1개의 답글
comment-user-thumbnail
2021년 12월 27일

mysql syntax 오류로 ? 이부분이 오류가나는데 어떻게 해야할가요?

답글 달기