Notice
Recent Posts
Recent Comments
Link
오늘도 개발
Node.js에서 인증, 인가 진행하기(bcrypt, jwt) 본문
1. 인증(회원가입)
1) req.body의 key 확인
js는 파이썬처럼 keyError가 없음. (없는 키 호출 시 undefined 반환)
직접 key가 있는지 없는지 확인해야 함.
Object.entries(딕셔너리)
딕셔너리의 키, 값을 리스트로 바꿔줌
const info = { username: 'garfield', password: '123' }
Object.entries(info) // [ [ 'username', 'garfield' ], [ 'password', '123' ] ]
배열.forEach(콜백함수)
배열을 iterate하며 콜백함수에 각 요소를 인자로 넣어 호출함
map과 달리 반환값이 없음.
const arr = [1, 2]
arr.forEach((val) => {
console.log(val * 10)
})
// 10
// 20
배열.includes(값)
배열에 어떤 값이 있는지 없는지 확인해서 true, false 반환
const arr = [1, 2, 3]
console.log(arr.includes(1)) // true
정리
const { username, password } = req.body; // { username: 'garfield', password: '123' }
// 1) 키값 체크 - hasKey 딕셔너리 채우기
const hasKey = { password: false, username: false };
const requireKey = Object.keys(hasKey); // ['password', 'username']
Object.entries(req.body).forEach((keyValue) => { // [ [ 'username', 'garfield' ], [ 'password', '123' ] ]
const [key, value] = keyValue;
if (requireKey.includes(key) && value){
hasKey[key] = true;
}
})
// 2) 키값 체크 - hasKey iterate하면서 값 없으면 400에러 반환하기
const hasKeyArray = Object.entries(hasKey); // [ [ 'password', 'true' ], [ 'username', 'true' ] ]
for (let i = 0; i < hasKeyArray.length; i++){
const [key, value] = hasKeyArray[i];
if (!value){
res.status(400).json({message: `${key}값이 없습니다`});
return;
}
}
2) bcrypt로 비밀번호 암호화하기
1. bcrypt 설치
npm install bcrypt
2. 코드 작성
async 함수 내에서 사용할 때는 genSalt, hash 메서드 대신 genSaltSync, hashSync 메서드 사용
// 1. 모듈 불러오기
const bcrypt = require('bcrypt');
const { username, password } = req.body; // { username: 'garfield', password: '123' }
// 2. 솔트값 생성
const salt = bcrypt.genSaltSync(12);
// 12는 솔트 횟수. 값 높을수록 보안 좋아지나 속도 저하
// $2a$12$B9cOW5a3MbEoqaiIRsXvjO
// 3. 해시 함수에 넣기
const hashedpw = bcrypt.hashSync(password, salt) // $2a$12$B9cOW5a3MbEoqaiIRsXvjOZTacL4uD6SCKjY1PpuAq/O0CGLLSLZe
3) 정리
app.post('/signup', async (req, res) => {
const { username, password } = req.body; // { username: 'garfield', password: '123' }
// 1) 키값 체크 - hasKey 딕셔너리 채우기
const hasKey = { password: false, username: false };
const requireKey = Object.keys(hasKey); // ['password', 'username']
Object.entries(req.body).forEach((keyValue) => { // [ [ 'username', 'garfield' ], [ 'password', '123' ] ]
const [key, value] = keyValue;
if (requireKey.includes(key) && value){
hasKey[key] = true;
}
})
// 2) 키값 체크 - hasKey iterate하면서 값 없으면 400에러 반환하기
const hasKeyArray = Object.entries(hasKey); // [ [ 'password', 'true' ], [ 'username', 'true' ] ]
for (let i = 0; i < hasKeyArray.length; i++){
const [key, value] = hasKeyArray[i];
if (!value){
res.status(400).json({message: `${key}값이 없습니다`});
return;
}
}
// 3) 비밀번호 암호화
const salt = bcrypt.genSaltSync(12);
const hashedPw = bcrypt.hashSync(password, salt)
try {
// 4) DB에 저장
await myDataSource.query(`
INSERT INTO users(username, password)
VALUES(?, ?)
`, [username, hashedPw]);
res.status(201).json({message: "userCreated"})
}
catch(err){
console.log(err)
res.status(500).json({message: "error"})
}
});
2. 인가(로그인)
1) req.body의 key 확인
회원가입과 마찬가지로 키 확인
const { username, password } = req.body; // { username: 'garfield', password: '123' }
const hasKey = { password: false, username: false };
const requireKey = Object.keys(hasKey); // ['password', 'username']
Object.entries(req.body).forEach((keyValue) => { // [ [ 'username', 'garfield' ], [ 'password', '123' ] ]
const [key, value] = keyValue;
if (requireKey.includes(key) && value){
hasKey[key] = true;
}
})
const hasKeyArray = Object.entries(hasKey); // [ [ 'password', 'true' ], [ 'username', 'true' ] ]
for (let i = 0; i < hasKeyArray.length; i++){
const [key, value] = hasKeyArray[i];
if (!value){
res.status(400).json({message: `${key}값이 없습니다`});
return;
}
}
2) db에서 대조할 유저 정보 가져오기
const [user] = await myDataSource.query(`
SELECT id, username, password
FROM users
WHERE username = ?
`, [username])
3) (유저가 있다면) 비밀번호 맞는지 확인
if (!user) {
console.log("NO_USER")
res.status(400).json({message: "NO_USER"})
}
// bcrypt로 비번 일치하는지 확인
const isPasswordCorrect = bcrypt.compareSync(password, user.password) // true or false
if (!isPasswordCorrect) {
res.status(400).json({message: "INVALID_PASSWORD"})
}
4) jwt 토큰 발급
1) jwt 설치
npm install jsonwebtoken
2) 코드 작성
// 최상단에서 모듈 임포트
const jwt = require('jsonwebtoken')
const token = jwt.sign({ userId: user.id }, 'secretKey');
res.status(200).json({message: 'LOGIN_SUCCESS', token: token})
5) 정리
const jwt = require('jsonwebtoken')
app.post('/login', async(req, res) => {
const { username, password } = req.body; // { username: 'garfield', password: '123' }
const hasKey = { password: false, username: false };
const requireKey = Object.keys(hasKey); // ['password', 'username']
Object.entries(req.body).forEach((keyValue) => { // [ [ 'username', 'garfield' ], [ 'password', '123' ] ]
const [key, value] = keyValue;
if (requireKey.includes(key) && value){
hasKey[key] = true;
}
})
const hasKeyArray = Object.entries(hasKey); // [ [ 'password', 'true' ], [ 'username', 'true' ] ]
for (let i = 0; i < hasKeyArray.length; i++){
const [key, value] = hasKeyArray[i];
if (!value){
res.status(400).json({message: `${key}값이 없습니다`});
return;
}
}
const [user] = await myDataSource.query(`
SELECT id, username, password
FROM users
WHERE username = ?
`, [username])
if (!user) {
console.log("NO_USER")
res.status(400).json({message: "NO_USER"})
}
const isPasswordCorrect = bcrypt.compareSync(password, user.password) // true or false
if (!isPasswordCorrect) {
res.status(400).json({message: "INVALID_PASSWORD"})
}
const token = jwt.sign({ userId: user.id }, 'secretKey');
res.status(200).json({message: 'LOGIN_SUCCESS', token: token})
})
참고
저스트코드 노드 + express 톺아보기
'웹 프로그래밍 > Javascript' 카테고리의 다른 글
| jest로 unit test하기 (0) | 2022.10.02 |
|---|---|
| Layered Pattern (0) | 2022.10.01 |
| Middleware (0) | 2022.09.28 |
| 에러/오류 핸들링 (0) | 2022.09.28 |
| 자바스크립트와 비동기 프로그래밍(콜백 함수, Promise, async/await) (0) | 2022.09.27 |