그동안은 DB를 만들 때 MySQL만 이용해 왔는데, 이번에 인프런 강의를 통해 MongoDB를 접하게 되었다.
아직 완전 겉핥기 수준이나, 어쨋든 지금까지 알게 된 내용들을 정리해보려 한다.
cloud.mongoDB.com 에서 새 프로젝트를 만든 후, cluster 를 하나 생성한다.
난 aws 기반으로 freee tier DB를 생성해줬다.
그리고 내 IP를 화이트리스트에 등록해줘야 정상적으로 내 로컬 서버에서 접근할 수 있으므로,
클러스터 생성 후에는 좌측 Network Access 카테고리에 들어가 IP등록까지 마쳐준다.
로직의 시작점이 되는 index.js에서 우선 DB를 우리 서버와 연결해야겠지?
mongoose 라는 ODM 을 사용하며, connect 메소드의 첫 번째 인자로 들어오는 내 DB의 URI는
해당 파일들을 git에서 관리하기 위해 config 폴더에 따로 담아두고 변수로서 불러오고 있다.
두 번째 인자로 들어오는 객체는 아직 뭔지 다 모르겠지만 최신버전의 mongoDB를 사용할 때 오류가 발생하지 않게 하기 위한 조치들이라고 한다. 일단 그런가보다 하고 넘어가고, 나중에 문제생기면 그 때 공부해보려고.
const mongoose = require("mongoose");
const config = require("./config/key");
mongoose
.connect(config.mongoURI, {
useNewUrlParser: true,
useUnifiedTopology: true,
useCreateIndex: true,
useFindAndModify: false,
})
.then(() => console.log("MongoDB Connected..."))
.catch(err => console.log(err));
이제 모델을 생성할 차례다.
여기서 이루어지는 것은, 앞으로 User 라는 이름의 테이블을 다음과 같은 칼럼들을 이용해 구성하겠다~ 하는 선언이다.
mongoose에 내장된 Schema 메소드를 사용하여 몇 가지 칼럼들을 만들고, 간단한 속성들을 부여했다.
그리고나서 model 메소드를 이용해 방금 만든 스키마를 활용한 User 모델을 만들어내고, User 라는 변수에 담았다. 이제 exports 하면 외부에서 해당 모델을 이용해 User 테이블에 데이터를 추가할 수 있게 된다.
const mongoose = require("mongoose");
const userSchema = mongoose.Schema({
name: {
type: String,
maxLength: 50,
},
email: {
type: String,
// 문자열 사이의 스페이스바 공간을 없앰
trim: true,
},
password: {
type: String,
minlength: 5,
},
lastname: {
type: String,
maxlength: 50,
},
role: {
// 넘버가 0이면 관리자, 1이면 일반유저 요런 느낌
type: Number,
default: 0,
},
image: String,
// DB 에 토큰이랑 토큰만료일까지 넣어서 관리함
token: {
type: String,
},
tokenExp: {
type: Number,
},
});
// 위에 짠 스키마를 바탕으로 User 라는 이름의 db모델을 생성
const User = mongoose.model("User", userSchema);
// 딴데서 갖다쓸수도 있도록 문 오픈
module.exports = { User };
포스트맨에서 /api/users/register 엔드포인트에, body에 email과 password 객체를 json 형태로 post 요청을 보내면 서버에서는 아래와 같은 동작들을 수행한 뒤, { success: true } 라는 객체를 보내줄 것이다.
app.post("/api/users/register", (req, res) => {
// 회원가입 할 때 필요한 정보들을 client에서 가져오면
// 그것들을 DB에 넣어준다.
const user = new User(req.body);
/*
console.log(user) 찍어보면 ?
{
role: 0,
_id: 606327b00f66fec650869b4a,
email: 'test4@gmail.com',
password: '12345'
}
*/
// MongoDB 의 save메소드. 위의 user 객체가 본격적으로 DB에 저장됨
user.save((err, userInfo) => {
if (err) return res.json({ success: false, err });
return res.status(200).json({
success: true,
});
});
});
그런데 DB에 고객의 password가 그대로 저장되면 보안상 영 껄끄럽기 때문에, save 메소드가 실행되기 전에 password를 암호화한 후, 암호화된 password를 save할 수 있으면 더 좋겠다.
bcrypt는 그걸 가능하게 해주는 라이브러리이며, 데이터에 salt를 팍팍 쳐서 본래의 맛을 감춰준다.
saltRounds 는 소금을 몇 바퀴 두를 것인지 정하며, genSalt 메소드를 이용해 작업을 수행한다.
const bcrypt = require("bcrypt");
// salt 가 몇 글자인지 지정. 이걸 이용해서 암호화함
const saltRounds = 10;
// user 모델에 save하기 전에 콜백함수를 실행하겠다는 선언
userSchema.pre("save", function (next) {
var user = this;
// 나중에 유저정보를 수정할 때 매번 암호화 함수가 실행되면 낭비이므로
// password 에 변동이 생겼을 때에만 이하의 함수를 실행시키겠다는 선언
if (user.isModified("password")) {
// 소금 생성! 콜백함수의 salt 인자에 담긴다.
bcrypt.genSalt(saltRounds, function (err, salt) {
if (err) return next(err);
// 소금이 생성되었으므로 password에 뿌리기 시작! hash 메소드를 사용
// 콜백함수의 hash -> 암호화된 비밀번호
bcrypt.hash(user.password, salt, function (err, hash) {
if (err) return next(err);
// 현재 '12345'라고 되어있는 user.password 를 암호화된 것으로 교체
user.password = hash;
next();
});
});
} else {
// password가 변동된게 아닌 경우 그냥 다음 갈 길 이어가기
next();
}
});