- 전체 코드
const { useSelect, userInsert } = require("../models");
const bcrypt = require("bcrypt");
const createHash = (password) => {
return new Promise((res, rej) => {
bcrypt.hash(password, 10, (err, data) => {
if (err) {
rej(err);
} else {
res(data);
}
});
});
};
const compare = (password, hash) => {
return new Promise((res, rej) => {
bcrypt.compare(password, hash, (err, same) => {
res(same);
});
});
};
exports.SignUp = async (req, res) => {
const { user_id, user_pw } = req.body;
try {
const hash = await createHash(user_pw);
await userInsert(user_id, hash);
res.redirect("/login");
} catch (error) {
console.log("SignUp in userControllers");
}
};
exports.Login = async (req, res) => {
const { user_id, user_pw } = req.body;
try {
const data = await useSelect(user_id);
if (!data?.user_id) {
return res.send("id 없음");
}
const compare_pw = await compare(user_pw, data.user_pw);
if (!compare_pw) {
return res.send("비밀번호가 틀렸습니다.");
}
res.send("로그인 됨");
} catch (error) {
console.log("Login inuserController", error);
}
};
- bcrypt를 이용한 해쉬 생성
const createHash = (password) => {
return new Promise((res, rej) => {
bcrypt.hash(password, 10, (err, data) => {
if (err) {
rej(err);
} else {
res(data);
}
});
});
};
- 해쉬를 만드는 함수이다.
- 해쉬를 만드는 일은 오래걸리기 때문에 비동기적으로 처리할 필요가있다.
- 따라서 promise를 반환한다.
- hash의 첫번째 매개변수는 해쉬화 할 비밀번호, 두번째 매개변수는 키 스트레칭 횟수이다.
- 만들어진 hash의 형식이다.
- salt는 기존 비밀번호에 임의의 데이터를 더해 해쉬화 하여 보안을 강화 하는 것이다.
- 처음 algorithm은 bcrypt에서 지정한 알고리즘의 종류다.
- 입력한 비밀번호와 mysql에 저장한 hash와 비교
const compare = (password, hash) => {
return new Promise((res, rej) => {
bcrypt.compare(password, hash, (err, same) => {
res(same);
});
});
};
- bcrypt.compare 함수를 이용해서 편하게 비교할 수 있다.
- 첫번째 매개변수는 유저가 입력한 비밀번호,두번째 매개변수는 mysql에 저장된 해쉬화된 유저의 비밀번호이다.
- 판별 여부에 따라 다르면 same=false,같은면 same=true가 할당된다.
- 회원가입에 적용
exports.SignUp = async (req, res) => {
const { user_id, user_pw } = req.body;
try {
const hash = await createHash(user_pw);
await userInsert(user_id, hash);
res.redirect("/login");
} catch (error) {
console.log("SignUp in userControllers");
}
};
- promise가 반환되기 때문에 당연히 await 키워드를 붙였고, 해당 값을 비밀번호 매개변수에 넣는다.
- 로그인에 적용
exports.Login = async (req, res) => {
const { user_id, user_pw } = req.body;
try {
const data = await useSelect(user_id);
if (!data?.user_id) {
return res.send("id 없음");
}
const compare_pw = await compare(user_pw, data.user_pw);
if (!compare_pw) {
return res.send("비밀번호가 틀렸습니다.");
}
res.send("로그인 됨");
} catch (error) {
console.log("Login inuserController", error);
}
};
- data.user_pw는 해쉬화된 비밀번호이므로 compare의 두번째 매개변수로 넣는다.
- 반환 값 (resolve)는 boolean타입 이므로 false일 경우 비밀번호가 틀렸다고 전달한다.
💡 예전에 spring security를 쓰면서 해쉬에대해 짤막하게 독학했던 기억이 난다.
스프링에 비해서 훨씬 쉬운 방법으로 암호화를 하고, 비교또한 간편한 것 같다.
라이브러리에 의해 필수요소들이 간편화 되어가고 있지만 그 원리를 정확히 이해하는것이 중요한 것 같다. 특히 salt부분은 더 정확한 이해를 할 필요가 있다.
항상 좋은 글 감사합니다.