on
Node.js 스터디 2주차
Node.js 스터디 2주차
비밀번호 보호
개발할때 두 가지 환경에서 할 수 있음
1. Local 환경(local developement)
2. deploy(배포) 한 후 -> Heroku 같은 사이트 이용
// dev.js module.exports={ mongoURI: 'mongodb+srv:mongodb+srv://olivia:[email protected]/myFirstDatabase?retryWrites=true&w;=majority' }
// key.js if(process.env.NODE_ENV === 'production'){ // ENODE_ENV: 환경변수 module.exports = require('./prod'); }else{ module.exports = require('./dev'); }
// prod.js module.exports = { mongoURI: process.env.MONGO_URI }
// index.js const config = require('./config/key'); mongoose.connect(config.mongoURI) .then(() => console.log('MongoDB Connected...')) // 연결 확인 .catch((e) => console.log('MongoDB error: ',e)); // error 발생시 보여주게 함
dev.js 파일은 .gitignore에 추가
// .gitignore node_modules dev.js
변경사항에 dev.js는 없음!
config 파일에 dev.js 없음!
Bcrypt 로 비밀번호를 암호화 하기
-> bcrypt 라이브러리 다운: npm install bcrypt --save
https://www.npmjs.com/package/bcrypt
- bcrypt로 비밀번호 암호화 하는 순서
1. Register Route로 가기: 정보들을 save하기 전에 먼저 비번를 암호화 해야함(mongoose 기능 이용)
2. 유저 정보를 DB에 저장하기 전으로 이동해 암호화
3. bcrypt의 salt를 이용해 비번 암호화
// User.js const bcrypt = require('bcrypt'); const saltRounds = 10 // pre()는 mongoose에서 가져온 메소드 userSchema.pre('save', function(next){ // User의 정보를 저장하기 전에 함수 실행 var user = this; // userSchema를 나타냄 // 비밀번호를 변경할 경우에만 암호화하기 위해서 if(user.isModified('password')){ // 비밀번호를 암호화시킴 bcrypt.genSalt(saltRounds, function(err, salt) { if(err) return next(err) bcrypt.hash(user.password, salt, function(err, hash) { if(err) return next(err) user.password = hash; // hash로 비번을 바꿈 next() // 돌아가기 }); }); } else{ next() } })
암호화 성공!
로그인 기능 만들기
1. login route 만들기
2. DB에서 요청한 E-mail 찾기: User.findOne() & 비번 동일여부 확인: Bcrypt 이용해 plain pw와 암호화된 hash pw 동일 여부 확인
3. 동일하다면 Token 생성: JSONWEBTOKEN 라이브러리 다운: npm install jsonwebtoken --save
https://www.npmjs.com/package/jsonwebtoken
4. 쿠키를 이용하기 위해 다운: npm install cookie-parser --save
// index.js const bodyParser = require('body-parser'); const cookieParser = require('cookie-parser'); app.use(cookieParser()); app.post('/api/users/login', (req, res) => { // 요청된 이메일을 데이터 베이스에 있는지 확인 User.findOne({email: req.body.email}, (err, user)=> { if(!user) {// 이메일을 가진 user가 없다면 return res.json({ loginSuccess: false, message: "제공된 이메일에 해당하는 유저가 없습니다." }) } // user가 있다면 요청된 이메일이 데이터 베이스에 있다면 비번이 맞는 비번인지 확인 user.comparePassword(req.body.password, (err, isMatch) => { // 메소드는 User.js(user model) 에서 생성 if(!isMatch) // 비번이 틀린 경우 return res.json({loginSuccess: false, message: "비밀번호가 틀렸습니다."}) // 비밀번호가 맞다면 Token 생성하기 user.generateToken((err, user) => { if(err) return res.status(400).send(err); // token을 쿠키에 저장 res.cookie("x_auth", user.token) .status(200) // 성공 .json({loginSuccess: true, userId: user._id}) }) }) }) })
// User.js const jwt = require('jsonwebtoken'); userSchema.methods.generateToken = function(cb){ var user = this; // 유저의 id 넣어줌 // jsonwebtoekn을 이용해 token 생성 var token = jwt.sign(user._id.toHexString(), 'secretToken') user.token = token user.save(function(err, user){ if(err) return cb(err) cb(null, user) }) }
Auth 기능 만들기
1. 쿠키에서 저장된 토큰을 서버에서 가져와 복호화
2. 복호화하면 유저의 id가 나오는데 그 id를 이용해 데이터베이스 user collection에서 유저를 찾은 후 쿠키에서받아온 토큰이 유저도 갖고 있는지 확인
// index.js const { auth} = require('./middleware/auth'); // role 0 -> 일반 유저 role 0이 아니면 관리자 app.get('api/users/auth', auth, (req, res) => { // 여기까지 미들웨어를 통과했다는 의미는 Authentication이 True라는 의미 res.status(200).json({ _id: req.user._id, isAdmin: req.user.role === 0 ? false: true, isAuth: true, email: req.user.email, name: req.user.name, lastname: req.user.lastname, role: req.user.role, image: req.user.image }) })
// auth.js const { User } = require('../models/User'); let auth = (req, res, nex) => { // 인증 처리를 하는 곳 // 클라이언트 쿠키에서 토큰 가져오기 let token = req.cookies.x_auth; // 토큰을 복호화 한 후 유저 찾기 User.findByToken(token, (err, user)=>{ if(err) throw err; if(!user) return res.json({isAuth: false, error: true}) req.token = token; req.user = user; next(); }) // 유저가 있으면 인증 Ok // 유저가 없으면 인증 No } module.exports = {auth};
// User.js userSchema.statics.findByToken = function(token,cb){ var user = this; // 토큰을 decode 하기 jwt.verify(token, 'secretToken', function(err, decoded){ // 유저 아이디를 이용해서 유저를 찾은 후 클라이언트에서 가져온 토큰과 DB에 보관된 토큰이 일치하는지 확인 user.findOne({"_id": decoded, "token": token}, function(err, user){ if(err) return cb(err); cb(null, user); }) }) }
로그아웃 기능 만들기
1. 로그아웃 Route 만들기
2. 로그아웃 하려는 유저를 데이터베이스에서 찾아 토큰 지우기
// index.js app.get('/api/users/logout', auth, (req, res) => { User.findOneAndUpdate({ _id: req.user._id}, {token: ""}, (err, user) => { if(err) return res.json({success: false, err}); return res.status(200).send({ success: true }) }) })
로그인 로그아웃 token 삭제됨!
from http://tistory-itolivia.tistory.com/334 by ccl(A) rewrite - 2021-09-20 17:26:53