비밀번호 암호화
https://tlseoqja.tistory.com/51
[Node] 회원 가입 시 비밀번호 암호화
MongoDB 연동 및 회원 가입 기능 구현 https://tlseoqja.tistory.com/49 [Node] node.js 서버와 MongoDB 연동하기 (mongoose) Mongoose란? Mongoose 라이브러리는 MongoDB란 NoSQL DB를 Node.js에서 사용할 수 있게 도와주는 라이
tlseoqja.tistory.com
JWT
JWT(Json Web Token)은 Json 객체에 인증이 필요한 정보들을 담은 후 비밀키로 서명한 토큰이다.
웹 표준을 따르고 있으며, 공식적으로 인증(Authentication) & 허가(Authorization) 방식으로 사용된다.
필요한 모든 정보를 하나의 객체에 담아서 전달하기 때문에 JWT 한 가지로 인증을 마칠 수 있다.
JWT의 장점 중 하나로 웹 표준을 따르기 때문에 대부분의 언어가 JWT를 지원한다.
대부분 사용자 인증과 로그인 유지 위해 사용한다.
더욱 자세한 내용은 아래 블로그를 참고하면 된다.
https://velog.io/@chuu1019/%EC%95%8C%EA%B3%A0-%EC%93%B0%EC%9E%90-JWTJson-Web-Token
😎 알고 쓰자, JWT(Json Web Token).
jwt 토큰이 어떻게 구성되어있는지, 왜 jwt 토큰을 사용해야하는지 아시나요?
velog.io
로그인 시 비밀번호 복호화 및 일치 확인
index.js 회원 가입 밑에 로그인 코드를 작성해준다.
// index.js
...
app.post("/api/users/register", (req, res) => {
...
});
app.post("/api/users/login", (req, res) => {
});
app.listen(port, () => console.log(`Example app listening on port ${port}!`));
우선 작성해야할 로직은 다음과 같다.
- 입력받은 email 정보가 DB에 존재하는지 여부를 판단
- 요청된 email이 있다면 비밀번호가 일치하는지 확인
- 비밀번호가 맞다면 토큰 생성
- 토큰 저장
1. email 정보 DB 존재 여부 판단
User 스키마의 함수인 findOne()을 사용해서 DB의 email 존재 여부를 판단한다.
// index.js
app.post("/api/users/login", (req, res) => {
User.findOne({ email: req.body.email })
.then(( user ) => {
if( !user ) {
return res.json({
loginSuccess: false,
message: "해당 이메일 정보가 없습니다.",
});
}
});
});
app.listen(port, () => console.log(`Example app listening on port ${port}!`));
해당 api로 데이터를 보내서 테스트해본다.
이메일이 존재하는 경우 다음 로직을 작성하지 않아서 포스트맨에서 무한로딩에 걸릴 것이고,
이메일이 존재하지 않는 경우 리턴된 json 값이 포스트맨에 찍힐 것이다.
2. email 존재 시 비밀번호 일치 확인
email이 존재한다면 입력받은 비밀번호가 일치하는지 확인하는 작업이 필요하다.
하지만 입력받은 비밀번호와 DB 내의 비밀번호는 비교하지 않아도 다를 것이다.
이유는 비밀번호를 암호화한 후 DB에 등록했기 때문이다.
그렇다면 입력받은 비밀번호와 복호화된 DB 비밀번호를 비교하는 동작이 필요하다.
다음은 스키마에서 비밀번호 비교 함수를 생성하고, 로그인 시 사용하는 방법이다.
2-1. 비밀번호 비교 함수 생성
User.js에서 이전에 작성한 pre() 함수 밑에 다음 코드를 추가해준다.
// User.js
...
userSchema.pre("save", function(next) {
...
});
userSchema.methods.comparePassword = function(plainPassword, cb) {
// 입력받은 비밀번호: 1234, 암호화된 비밀번호: $2b$10$Os6KqEFfTp9P9pM.S8Ddp.skwg0ehBla1JXl9AhkUn8JGppm7LQ3m
bcrypt.compare(plainPassword, this.password ,function(err, isMatch) {
if( err ) return cb(err);
cb(null, isMatch);
});
};
입력받은 비밀번호와 DB의 암호화된 비밀번호를 bcrypt 라이브러리를 이용해서 비교하는 함수이다.
비교 후 callback 함수를 통해 에러가 있을 경우 err만을 리턴하고,
비밀번호가 일치할 경우 isMatch를 리턴해준다.
2-2. 비밀번호 비교 함수 적용
index.js에서 email 정보가 존재한 경우 비밀번호 함수 로직을 실행하도록 코드를 작성한다.
// index.js
app.post("/api/users/login", (req, res) => {
// 요청된 이메일을 DB에서 존재하는지 확인
User.findOne({ email: req.body.email })
.then(( user ) => {
if( !user ) {
return res.json({
loginSuccess: false,
message: "해당 이메일 정보가 없습니다.",
});
}
// 요청된 이메일이 DB에 있다면 비밀번호가 일치하는지 확인
user.comparePassword(req.body.password, (err, isMatch) => {
if(!isMatch) {
return res.json({
loginSuccess: false,
message: "비밀번호가 일치하지 않습니다.",
});
}
});
});
});
포스트맨으로 비밀번호를 틀리게 입력한 후 보냈을 때의 화면이다.
3. 비밀번호 일치 시 JWT 토큰 생성
email이 존재하고 비밀번호가 일치한다면 로그인이 된 상태라고 할 수 있다.
앞서 언급한 사용자 인증과 로그인 상태를 관리하기 위해 JWT를 발급을 진행한다.
JWT 라이브러리를 설치해준다.
npm install jsonwebtoken
3-1. JWT 토큰 생성 함수 작성
JWT 토큰을 생성하기 위해 User.js에 다음 코드를 작성해준다.
// User.js
import jwt from "jsonwebtoken";
...
userSchema.methods.comparePassword = function(plainPassword, cb) {
...
};
userSchema.methods.generateToken = function(cb) {
// jsonwebtoken을 이용해서 토큰 생성
const user = this;
const token = jwt.sign(user._id.toHexString(), "secretToken");
user.token = token;
user.save()
.then((user, err) => {
if( err ) return cb(err);
cb(null, user);
});
};
JWT의 sign함수를 통해 DB에서 생성된 _id값과 시크릿 키를 이용해서 JWT 토큰을 생성했다.
생성된 토큰은 user 객체의 token 값에 넣어서 save해주었다.
3-2. JWT 생성 함수 적용
작성한 함수를 index.js에 다음과 같이 추가해준다.
// index.js
app.post("/api/users/login", (req, res) => {
console.log("/api/users/login");
// 요청된 이메일을 DB에서 존재하는지 확인
User.findOne({ email: req.body.email })
.then((user) => {
if( !user ) {
return res.json({
loginSuccess: false,
message: "해당 이메일 정보가 없습니다.",
});
}
// 요청된 이메일이 DB에 있다면 비밀번호가 일치하는지 확인
user.comparePassword(req.body.password, (err, isMatch) => {
if(!isMatch) {
return res.json({
loginSuccess: false,
message: "비밀번호가 일치하지 않습니다.",
});
}
// 비밀번호까지 맞다면 토큰 생성
user.generateToken((err, user) => {
if(err) {
return res.status(400).send(err);
}
console.log(user);
});
});
});
});
포스트맨으로 email과 password를 전달해서 로그인 테스트를 진행해본다.
로그인 성공 시 다음과 같이 DB에 JWT token이 잘 저장된 것을 확인할 수 있다.
4. JWT 토큰 저장
로그인 정보를 저장할 때 세션, 쿠키, 스토리지를 사용할 수 있다.
각 저장소마다 특징과 장단점이 존재하지만 간단히 설명하면 다음과 같다.
Local Storage
• 브라우저를 종료해도 명시적으로 삭제하지 않는 이상 영구적으로 저장된다.
Session
• 브라우저가 서버에 연결돼있는 동안 유지하는 데이터 집합이다.
• 메모리에 존재하기 때문에 브라우저가 종료되면 데이터가 삭제된다.
Cookie
• 클라이언트가 서버에 방문한 정보를 클라이언트단에 저장하는 작은 파일이다.
• 클라이언트의 브라우저 메모리 또는 하드디스크에 저장된다.
• 데이터의 유효시간을 설정할 수 있고, 대부분의 브라우저가 지원한다.
더욱 자세한 내용은 아래 블로그를 참고하면 된다.
https://joyhong-91.tistory.com/51
쿠키, 세션, 웹 스토리지 차이 (cookie, session, web storage)
1. 쿠키, 웹스토리지 (로컬스토리지, 세션스토리지) 생성 배경 HTTP는 요청과 응답을 주고 받아 한 사이클이 종료되면 연결이 끊어지는 무상태성을 가지고 있기 때문에 클라이언트의 상태를 보존
joyhong-91.tistory.com
이번 프로젝트에선 cookie에 JWT 토큰을 저장하도록 하겠다.
쿠키를 사용하기 위해 라이브러리를 설치해준다.
npm install cookie-parser
4-1. cookie-parser
cookie-parser는 요청된 쿠키를 쉽게 추출할 수 있도록 도와주는 미들웨어이다.
express의 request 객체에 cookie속성이 부여될 수 있게 index.js안에 다음 코드를 추가해준다.
// index.js
import cookieParser from "cookie-parser";
...
// application/x-www-form/urlencoded
app.use(bodyParser.urlencoded({extended: true}));
// application/json
app.use(bodyParser.json());
app.use(cookieParser());
...
4-2. 로그인 성공 시 토큰 값 쿠키 저장
index.js의 로그인 함수에 JWT 토큰을 쿠키에 저장해주는 코드를 추가해준다.
회원 로그인 전체 코드는 다음과 같다.
app.post("/api/users/login", (req, res) => {
console.log("/api/users/login");
// 요청된 이메일을 DB에서 존재하는지 확인
User.findOne({ email: req.body.email })
.then((user) => {
if( !user ) {
return res.json({
loginSuccess: false,
message: "해당 이메일 정보가 없습니다.",
});
}
// 요청된 이메일이 DB에 있다면 비밀번호가 일치하는지 확인
user.comparePassword(req.body.password, (err, isMatch) => {
if(!isMatch) {
return res.json({
loginSuccess: false,
message: "비밀번호가 일치하지 않습니다.",
});
}
// 비밀번호까지 맞다면 토큰 생성
user.generateToken((err, user) => {
if(err) {
return res.status(400).send(err);
}
// 토큰 저장 -> 쿠키
res.cookie("x_auth", user.token)
.status(200)
.json({
loginSuccess: true,
userId: user._id,
});
});
});
});
});
로그인 테스트
포스트맨으로 로그인 정보를 넣고 해당 API로 전송 성공 화면은 아래와 같다.
'🖥️Frontend > Node' 카테고리의 다른 글
[Node] 로그아웃 기능 구현 (0) | 2023.12.01 |
---|---|
[Node] 페이지 접속 시 JWT 토큰 인증 (0) | 2023.11.30 |
[Node] 회원 가입, 비밀번호 암호화 (2) | 2023.11.28 |
[Node] nodemon 설치 (자동 코드 반영) (1) | 2023.11.28 |
[Node] node.js 서버와 MongoDB 연동하기 (mongoose) (2) | 2023.11.23 |
댓글