#8 Nodemon 설치
Nodemon 이란 ?
소스를 변경할 때 자동으로 감지해서 서버를 재시작해주는 툴
Nodemon 설치
npm install nodemon --save-dev
* -dev는 로컬에서만 개발할 때 사용하겠다는 의미
Nodemon 스크립트 추가
// package.jsaon
"scripts" {
"backend": "nodemon index.js",
}
$ npm run backend
backend 스크립트로 서버를 구동시키면 index.js가 Nodemon으로 열림 ( 코드 수정 후 서버 재시작 필요 X )
#9 비밀 설정 정보 관리
비밀 설정 정보 가리기
소스코드 내에 포함된 비밀번호 등이 Git Hub에 공개되지않도록 하기
Local 환경 or Deploy(배포) 후
두 경우를 따로 생각해야함
development(Local) 모드인 경우 소스코드 내에서 변수를 가져갈 수 있음
production(Deploy) 모드인 경우 클라우드 사이트 내에서 변수를 관리해야함
config 폴더 생성
key.js 작성
if(process.env.Node_ENV == 'production') { // 환경 변수
module.exports = require('./prod') // production 모드면 prod.js 파일에서 가져오기
}
else {
module.exports = require('./dev') // development 모드면 dev.js 파일에서 가져오기
}
dev.js 작성
module.exports = {
mongoURI: 'mongodb+srv://jione:<password>@jione.2qflm.mongodb.net/test?retryWrites=true&w=majority'
} // index.js에서 가져오기
prod.js 작성
module.exports = {
mongoURI: process.env.MONGO_URI // MONGO_URI 변수는 클라우드 사이트에서 설정
}
index.js 수정
const config = require('./config/key') // config 정의
mongoose.connect('config.mogoURI', { // config의 mongoURI
useNewUrlParser: true, useUnifiedTopology: true, useCreateIndex: true, useFindAndModify: false
}).then(()=>console.log('MogoDB Connected...'))
.catch(err => console.log(err))
.gitignore 수정
dev.js
remote에 push 하면 dev.js 은 제외되어 올라감 ( 비밀번호 보호 )
#10 Bcrypt로 비밀번호 암호화 하기
Mongo DB의 collections 확인 해보기
Bcrypt 라이브러리 다운로드
$ npm install bcrypt --save
비밀번호 암호화하기
// User.js에 추가
const bcrypt = require('bcrypt')
const saltRounds = 10 // salt가 몇 글자 인지 설정
userSchema.pre('save',function( next ) {
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 // 암호화가 성공하면 password를 hash로 교체
next()
})
})
}
else {
next() // 비밀번호가 변경되지않으면 넘어감
}
})
salt를 사용해 암호화
bcrypt를 이용한 비밀번호 암호화 테스트
비밀번호가 암호화된 hash값으로 저장됨
#11 로그인 기능 with Bcrypt (1)
Login Route 만들기
1. 데이터베이스에서 요청한 이메일 찾기
2. 데이터베이스에서 요청한 이메일이 있다면 비밀번호가 같은지 확인
3. 비밀번호까지 같다면 Token을 생성
이메일&비밀번호 확인
// index.js에 추가
app.post('/login',(req,res) => {
// 요청된 이메일이 데이터베이스에서 있는지 찾는다.
User.findOne({email : req.body.email},(err, user) =>{
if(!user){
return res.json({
loginSuccess: false,
message: "제공된 이메일에 해당하는 유저가 없습니다."
})
}
// 요청된 이메일이 데이터 베이스에 있다면 비밀번호가 맞는 비밀번호인지 확인.
user.comparePassword(req.body.password, (err,isMatch) => {
if(!isMatch) // 비밀번호가 같지않음
return res.json({loginSuccess:false, message: "비밀번호가 틀렸습니다."})
})
})
})
// User.js에 추가
userSchema.methods.comparePassword = function(plainPassword, cb) { // 비밀번호 비교 메소드
// plainPassword 1234567 암호화된 비밀번호 $2b$10$HW5QnqP3SE6Ux85ezceHJeKrSphylPCYB587mmeGeTBgpkP3YWomy
// plainPassword를 암호화해 비교해야함 복호화할 수 없음
bcrypt.compare(plainPassword,this.password,function(err,isMatch){
if(err) return cb(err), // 비밀번호가 같지않음
cb(null,isMatch) // 비밀번호가 같음
})
}
#12 토큰 생성 with jsonwebtoken
JSON WEB TOKEN 라이브러리 다운로드
$ npm install jsonwebtoken --save
Cookie Parser 다운로드
$ npm install cookie-parser --save
JWT 사용하기
https://www.npmjs.com/package/jsonwebtoken
토큰 생성하기
//index.js에 추가
const cookieParser = require('cookie-parser')
app.use(cookieParser())
// user.comparePassword안에 추가
// 비밀번호까지 맞다면 토큰을 생성하기.
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})
})
//User.js에 추가
userSchema.methods.generateToken = function(cb) {
var user = this
// jsonwebtoken을 이용해서 token을 생성하기
var token = jwt.sign(user._id.toHexString(), 'secretToken')
// user._id + 'secretToken' = token
// ->
// 'secretToken' -> user._id
user.token = token
user.save(function(err,user){ // user DB에 토큰 저장
if(err) return cb(err)
cb(null,user)
})
}
#13 Auth 기능 만들기
Authentication(인증)이 필요한 이유 ?
사이트의 페이지마다 로그인 여부, 유저의 권한에 따라 이용할 수 있는 범위가 다르기 때문
확인하는 방법 ?
전 강의에서 Token을 서버 사이드에서는 유저 정보 DB에 클라이언트 사이드에서는 Cookie에 저장했음
이 두가지 Token이 서로 맞는지 계속 체크
1. Cookie에 저장된 Token을 Server에 가져와서 복호화를 한다.
2. 복호화를 하면 User ID가 나오는데 그 User ID를 이용해 DB User Collection에서 유저를 찾은 후 쿠키에서 받아온 Token을 User도 갖고 있는지 확인
3. 일치하면 인증이 완료 되고 해당하는 요청을 제공
Auth Route 만들기
루트 디렉토리에 middleware 폴더 생성 -> auth.js 파일 생성
// User.js에 추가
userSchema.statics.findByToken = function(token,cb){
var user = this;
//user._id + 'secretToken' = token
// 토큰을 decode 한다.
jwt.verify(token,'secretToken',function(err,decoded){
// 유저 아이디를 이용해서 유저를 찾은 다음에
// 클라이언트에서 가져온 token과 보관된 토큰이 일치하는지 확인
user.findOne({"_id": decoded, "token": token},function(err,user){
if(err) return cb(err)
cb(null,user)
})
})
}
// auth.js
const { User } = require("../models/User");
let auth = (req,res,next) => {
// 인증 처리를 하는곳
// 클라이언트 쿠키에서 토큰을 가져온다.
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() // 미들웨어에 갇히지않게 다음으로 넘김
})
// 유저가 있으면 인증 Okay
// 유저가 없으면 인증 No !
}
module.exports = { auth };
// index.js에 추가
const {auth} = require('./middleware/auth')
app.get('/api/users/auth', auth , (req,res) =>{
// 여기까지 미들웨어를 통과해 왔다는 얘기는 Authentication이 True라는 말
req.status(200).json({
_id: req.user._id,
isAdmin: req.user.role === 0 ? false : true,
isAuth: true,
email: req.user.email,
name: req.user.name,
role: req.user.lastname
})
})
#14 로그아웃 기능
로그아웃 Route 만들기로그아웃하려는 유저를 데이터베이스에서 찾아서 그 유저의 토큰을 지워준다.
* 토큰을 지워주는 이유 ? 잘못된 인증이 발생하지않도록
// index.js에 추가
app.get('/api/users/logout', auth, (req,res) => { // 만들어놓은 auth 메소드 사용
User.findOneAndUpdate({_id: req.user.id}, // id를 찾아서
{token: ""}, // token을 지워줌
(err, user) => {
if (err) return res.json({ success: false, err}) // 에러가 난 경우
return res.status(200).send({ // 성공한 경우
success: true
})
})
})
'Web > Node.js' 카테고리의 다른 글
[인프런] Node JS #1 ~ #7 (0) | 2020.07.29 |
---|
댓글