- DB에서 요청한 e-mail찾기
- DB에서 요청한 e-mail이 있다면 비밀번호가 같은지 확인
- 비밀번호까지 같다면 Token을 생성
// 로그인 router 만들기 app.post('/login', (req, res) => { // 요청된 e-mail을 데이터베이스에 있는지 확인 // 현재 e-mail이 데이터베이스에 있다면, password도 맞는 지 확인 // 비밀번호까지 맞을 경우, Token 생성 });
요청된 이메일이 데이터 베이스에 있는지 찾기 위해서는 mongoose에 있는 findOne 메서드를 사용해서 찾아야 된다.
// 로그인 router 만들기 app.post('/login', (req, res) => {`` // 1. 요청된 e-mail을 데이터베이스에 있는지 확인 User.findOne({ email: req.body.email }, (err, userInfo) => { if(!userInfo) { return res.json({ loginSuccess: false, message: '제공된 이메일에 해당하는 사용자가 없습니다. :(' }); } }); });
사용자가 로그인 시 입력한 이메일이 데이터베이스에 있다면,
이제 비밀번호가 같은지 확인하는 작업이 필요하다.비밀번호가 같은 지 확인하는 작업은 User 모델에서 메소드를 하나 만들어서 확인 할 것이다.
우선 indes.js에서는 아래와 같은 작업이 필요하다.
// 로그인 router 만들기 app.post('/login', (req, res) => { // 1. 요청된 e-mail을 데이터베이스에 있는지 확인 User.findOne({ email: req.body.email }, (err, userInfo) => { if(!userInfo) { return res.json({ loginSuccess: false, message: '제공된 이메일에 해당하는 사용자가 없습니다. :(' }); } // 2. 현재 e-mail이 데이터베이스에 있다면, password도 맞는 지 확인 userInfo.comparePassword(req.body.password, (err, isMatch) => { if(!isMatch) { // 비밀번호가 틀린 경우 return res.json({ loginSuccess: false, message: '비밀번호가 틀렸습니다.' }); } }); }); });
비밀번호가 같은지 비교하는 함수를 User 모델에서 만들어 볼 것이다.
// comparePassword method userSchema.methods.comparePassword = function(plainPassword, callback) { // 로그인 시 입력한 비밀번호랑 데이터베이스에 있는 암호화된 비밀번호랑 같은지 비교하는 작업이 필요 // mongoose에서는 복호화하는 메서드가 없기 때문에 로그인 시 입력한 비밀번호를 암호화해서 데이터베이스에 있는 비밀번호와 먼저 같은 지 비교해야된다. bcrypt.compare(plainPassword, this.password, function(err, isMatch) { if(err) return callback(err); // 비밀번호가 같다. callback(null, isMatch); }); }
이제 비밀번호까지 같다는 것을 확인했으면, 사용자를 위한 Token을 생성해야된다.
토큰을 생성하기 위해서는 JSONWEBTOKEN이라는 라이브러리를 이용해야 된다.
$ npm install jsonwebtoken --save
jsonwebtoken npm 참고
https://www.npmjs.com/package/jsonwebtoken
jsonwebtoken을 import한 뒤
var jwt = require('jsonwebtoken');
sign 메소드로 합쳐주면 토큰이 생성된다.
var token = jwt.sign({ foo: 'bar' }, 'shhhhh');
const jwt = require('jsonwebtoken'); ... // generateToken method userSchema.methods.generateToken = function(callback) { let user = this; // jsonwebtoken을 이용해서 Token 생성하기 jwt.sign({ user._id}) };
user의 id를 가져오기 위해서 this로 user를 받아왔다.
그리고 id를 다룰 때는 DataBase에 있는 id를 다뤄야 되는데
mongoDB에서 id를 확인해 보니 컬럼명이_id
이렇게 만들어져있었다.
로그인 요청을 테스트하던 중 오류가 발생했다.
jwt.sign의 payload 부분에 user_.id를 넣었더니 아래와 같은 에러가 발생했다. 오류 문구는 아래의 사진과 같았다.
오류가 발생한 기존 코드
// generateToken method userSchema.methods.generateToken = function(callback) { let user = this; // user._id + 'secretToken' --> Token을 만든다. // 그리고 토큰을 해석할 때 'secretToken'를 넣으면, suer._id가 나온다. const token = jwt.sign(user._id, 'secretToken'); user.token = token; //userSchema의 token 필드에 생성한 토큰을 넣어준다. user.save(function(err, user) { if(err) return callback(err); callback(null, user); }); };
이것이 무슨 오류인지 검색해 보았는데 token을 만들 때 sign에서 받을 때,
plain object를 기대했는데 user._id는 그게 아니어서 발생한 에러였다.plain object를 만드는 방법
해결 방법으로는
user._id.toJSON(); user._id.toHexString(); JSON.stringify(user); Object.assign({}, user));
위와 같이 다양한 방법으로 해결 가능하다.
오류 해결 코드
userSchema.methods.generateToken = function(callback) { let user = this; const token = jwt.sign(user._id.toHexString(), 'secretToken'); user.token = token; user.save(function(err, user) { if(err) return callback(err); callback(null, user); }); };
token을 저장한다. 어디에 저장할지는 여러군데에 할 수 있지만
token을 cookie or localStorage or session 에 저장 할 수 있는데 cookie에 token 저장해 볼 것이다.cookie를 사용하기 위해서는 라이브러리를 추가해야 된다.
express에서 제공해주는 cookie-parser라는 것을 다운받아야 된다.
$ npm install cookie-parser --save
cookie에 token을 저장해 놓으면
아래의 cookie부분에 지정한 이름으로 token이 저장된다.
// 3. 비밀번호까지 맞을 경우, Token 생성 userInfo.generateToken((err, user) => { if(err) return res.status(400).send(err); // token을 저장한다. 어디에 저장할지는 여러군데에 할 수 있지만 // token을 cookie or localStorage or session 에 저장 할 수 있다. // cookie에 token 저장하기 res.cookie("x_auth", user.token) .status(200) .json({ loginSuccess: true, userId: user._id}); });
로그인 확인, 암호화 된 userId도 확인
쿠키에 토큰잘 저장되었는지 확인
따라하며 배우는 노드, 리액트 시리즈를 통해 개념을 익히면서 실습하고 있습니다.
https://bit.ly/3wGxKGC