๐Ÿ”ฅ/์‡ผํ•‘๋ชฐ ๋งŒ๋“ค๊ธฐ

[์‡ผํ•‘๋ชฐ ๋งŒ๋“ค๊ธฐ] Node JS - Section 0 ๋กœ๊ทธ์ธ / ๋กœ๊ทธ์•„์›ƒ ๊ธฐ๋Šฅ / Backend

say! 2022. 7. 4. 14:40
728x90

๐Ÿ“’ ์ฐธ๊ณ  ๊ฐ•์˜

 

[๋ฌด๋ฃŒ] ๋”ฐ๋ผํ•˜๋ฉฐ ๋ฐฐ์šฐ๋Š” ๋…ธ๋“œ, ๋ฆฌ์•กํŠธ ์‹œ๋ฆฌ์ฆˆ - ๊ธฐ๋ณธ ๊ฐ•์˜ - ์ธํ”„๋Ÿฐ | ๊ฐ•์˜

์ด ๊ฐ•์˜๋ฅผ ํ†ตํ•ด์„œ ๋ฆฌ์•กํŠธ์™€ ๋…ธ๋“œ๋ฅผ ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉํ•˜๋Š”์ง€ ๊ธฐ๋ณธ์ ์ธ ๋‚ด์šฉ๋“ค์„ ๋ฐฐ์šธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค., - ๊ฐ•์˜ ์†Œ๊ฐœ | ์ธํ”„๋Ÿฐ...

www.inflearn.com


๐ŸŸฃ๋กœ๊ทธ์ธ ๊ธฐ๋Šฅ
Node.js
Express JS : ์›น์‚ฌ์ดํŠธ, ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์‰ฝ๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ๊ฒŒ ๋„์™€์คŒ, framework for Node.js
index.js : ๋ฐฑ์—”๋“œ ์‹œ์ž‘์ 

 

Express "Hello World" example

Hello world example Embedded below is essentially the simplest Express app you can create. It is a single file app — not what you’d get if you use the Express generator, which creates the scaffolding for a full app with numerous JavaScript files, Jade

expressjs.com


mongoDB

 

MongoDB Atlas Database | Multi-Cloud Database Service

The multi-cloud database service at the heart of our application data platform that accelerates and simplifies how you build with data. Try MongoDB Atlas today!

www.mongodb.com


Mongoose : ๋ชฝ๊ณ DB๋ฅผ ํŽธํ•˜๊ฒŒ ์“ธ ์ˆ˜ ์žˆ๋Š” Object Modeling Tool


๐Ÿ˜Ž์—๋Ÿฌ ํ•ด๊ฒฐ๋ฒ•

MongoParseError: options usecreateindex, usefindandmodify are not supported

 

MongoParseError: options usecreateindex, usefindandmodify are not supported ์—๋Ÿฌ

Nodejs์—์„œ mongoDB์— ์—ฐ๊ฒฐ ์‹œ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์—๋Ÿฌ๊ฐ€ ๋‚˜ํƒ€๋‚ฌ๋‹ค. MongoParseError: options usecreatein...

blog.naver.com


Model : Schema๋ฅผ ๊ฐ์‹ธ๋Š” ์—ญํ• 

Git is the tool, GitHub is the service for projects that use Git
.gitignore ํŒŒ์ผ : git์—์„œ ๊ด€๋ฆฌํ•  ํ•„์š”์—†๋Š” ํŒŒ์ผ๋“ค ์ œ์™ธํ•˜๊ธฐ, ์ปค๋ฐ‹ ์‹œ ์ œ์™ธ
SSH : Secure Shell

#body parser ๋‹ค์šด๋ฐ›๊ธฐ
npm install body-parser --save

POST MAN ๋‹ค์šด

 

Download Postman | Get Started for Free

Try Postman for free! Join 20 million developers who rely on Postman, the collaboration platform for API development. Create better APIs—faster.

www.postman.com


#Node Mon ๋‹ค์šด๋กœ๋“œ
npm install nodemon --save-dev
-dev : development ๋ชจ๋“œ๋ฅผ ์˜๋ฏธ

#Bcrypt

Bcrypt ์ด์šฉํ•ด์„œ ๋น„๋ฐ€ ๋ฒˆํ˜ธ ์•”ํ˜ธํ™” ํ•ด์คŒ > ๋ฐ์ดํ„ฐ ๋ฒ ์ด์Šค์— ์ €์žฅ

npm install bcrypt --save

 

#Bcrypt๋กœ ๋น„๋ฐ€๋ฒˆํ˜ธ ์•”ํ˜ธํ™” ํ•˜๋Š” ์ˆœ์„œ

Register Route๋กœ ๊ฐ€๊ธฐ

์œ ์ € ์ •๋ณด๋“ค(Account, Password ๋“ฑ)์„ ๋ฐ์ดํ„ฐ ๋ฒ ์ด์Šค์— ์ €์žฅํ•˜๊ธฐ ์ „์—๊ฐ€ ์•”ํ˜ธํ™” ํ•  ํƒ€์ด๋ฐ

-user model์„ ์ €์žฅํ•˜๊ธฐ ์ „์— ์ˆ˜ํ–‰

User.js > saltRounds = salt๊ฐ€ ๋ช‡ ๊ธ€์ž์ธ์ง€ > salt ๋จผ์ € ์ƒ์„ฑ > salt๋ฅผ ์ด์šฉํ•ด์„œ ๋น„๋ฐ€๋ฒˆํ˜ธ ์•”ํ˜ธํ™”

const bcrypt = require('bcrypt');
const saltRounds = 10



userSchema.pre('save', function( next ){
  var user = this;

  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
        next()
      })
    });
  } else{ // ๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ์•„๋‹Œ ๋‹ค๋ฅธ ์ •๋ณด๋ฅผ ๋ฐ”๊ฟ€ ๊ฒฝ์šฐ์—๋Š” ๊ทธ๋ƒฅ next()๋กœ ์ด๋™
    next()
  }
  
});

 

 

bcrypt

A bcrypt library for NodeJS.. Latest version: 5.0.1, last published: a year ago. Start using bcrypt in your project by running `npm i bcrypt`. There are 3389 other projects in the npm registry using bcrypt.

www.npmjs.com

๋ชฝ๊ณ db > view monitoring > collections > password๊ฐ€ ์•”ํ˜ธํ™”๋œ ๊ฑธ ํ™•์ธ ๊ฐ€๋Šฅ

#login route ๋งŒ๋“ค๊ธฐ

1. ๋ฐ์ดํ„ฐ ๋ฒ ์ด์Šค์—์„œ ์š”์ฒญํ•œ email ์ฐพ๊ธฐ > User.findOne()

2. ๋ฐ์ดํ„ฐ ๋ฒ ์ด์Šค์—์„œ ์š”์ฒญํ•œ email์ด ์žˆ๋‹ค๋ฉด ๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ๊ฐ™์€์ง€ ํ™•์ธ > Bcrypt๋ฅผ ์ด์šฉํ•ด์„œ plain password์™€ ์•”ํ˜ธํ™”๋œ (Hashed) ํŒจ์Šค์›Œ๋“œ๊ฐ€ ๊ฐ™์€์ง€ ํ™•์ธ

3. ๋น„๋ฐ€๋ฒˆํ˜ธ๊นŒ์ง€ ๊ฐ™๋‹ค๋ฉด Token ์ƒ์„ฑ

> ํ† ํฐ ์ƒ์„ฑ์„ ์œ„ํ•ด JSONWEBTOKEN ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋‹ค์šด๋กœ๋“œ

npm install jsonwebtoken --save

 

 

jsonwebtoken

JSON Web Token implementation (symmetric and asymmetric). Latest version: 8.5.1, last published: 3 years ago. Start using jsonwebtoken in your project by running `npm i jsonwebtoken`. There are 19984 other projects in the npm registry using jsonwebtoken.

www.npmjs.com

#ํ† ํฐ ์ฟ ํ‚ค์— ์ €์žฅํ•˜๊ธฐ

npm cookie-parser --save

*index.js

app.post('/api/users/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.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.comparePassword = function(plainPassword, cb){

  // plainPassword 1234567    ์•”ํ˜ธํ™”๋œ ๋น„๋ฐ€๋ฒˆํ˜ธ $2b$10$L4PZZ8meTLucmN0ZsxunlOvHap2w7Lxb5Xt0yB5aNYDAiw1pSqQUy
  bcrypt.compare(plainPassword, this.password, function(err, isMatch){
    if(err) return cb(err);
      cb(null, isMatch)
  })
}


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){
    if(err) return cb(err)
    cb(null, user)
  })
}

 

#Auth route ๋งŒ๋“ค๊ธฐ

๋กœ๊ทธ์ธํ•œ ์‚ฌ์šฉ์ž๋งŒ ๋“ค์–ด๊ฐˆ ์ˆ˜ ์žˆ๋Š” ํŽ˜์ด์ง€ / ๊ด€๋ฆฌ์ž๋งŒ ๋ณผ ์ˆ˜ ์žˆ๋Š” ํŽ˜์ด์ง€.... ๋“ฑ์˜ ๊ธฐ๋Šฅ์„ ์ด์šฉํ•˜๊ธฐ ์œ„ํ•ด ๋งŒ๋“ฆ

1. Cookie์—์„œ ์ €์žฅ๋œ Token์„ Server์—์„œ ๊ฐ€์ ธ์™€์„œ ๋ณตํ˜ธํ™” Decode

2. ๋ณตํ˜ธํ™”๋ฅผ ํ•˜๋ฉด User ID๊ฐ€ ๋‚˜์˜ค๋Š”๋ฐ ๊ทธ User ID๋ฅผ ์ด์šฉํ•ด์„œ ๋ฐ์ดํ„ฐ ๋ฒ ์ด์Šค User Collection์—์„œ ์œ ์ €๋ฅผ ์ฐพ์€ ํ›„ ์ฟ ํ‚ค์—์„œ ๋ฐ›์•„์˜จ token์ด ์œ ์ €๋„ ๊ฐ–๊ณ ์žˆ๋Š”์ง€ ํ™•์ธ

> ์ฟ ํ‚ค๊ฐ€ ์ผ์น˜X > Authentication False

> ์ฟ ํ‚ค ์ผ์น˜ > Authentication True

*middleware ํด๋” ์† 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})


     // ์œ ์ € ์žˆ์œผ๋ฉด ์ธ์ฆ Okay  ์œ ์ € ์—†์œผ๋ฉด ์ธ์ฆ No
    req.token = token;
    req.user = user;
    next();

  })

}

module.exports = { auth };

*User.js

userSchema.statics.findByToken = function(token, cb){
  var user = this;

  //user._id + '' = token
  // ํ† ํฐ์„ decode ๋ณตํ˜ธํ™”ํ•˜๊ธฐ
  jwt.verify(token, 'secretToken', function(err, deoded){
    // ์œ ์ € ์•„์ด๋””๋ฅผ ์ด์šฉํ•ด์„œ ์œ ์ €๋ฅผ ์ฐพ์€ ๋‹ค์Œ์—
    // ํด๋ผ์ด์–ธํŠธ์—์„œ ๊ฐ€์ ธ์˜จ token๊ณผ DB์— ๋ณด๊ด€๋œ token์ด ์ผ์น˜ํ•˜๋Š”์ง€ ํ™•์ธ

    user.findOne({"_id":decoded, "token": token}, function(err, user){
      if(err) return cb(err);
      cb(null, user)
    })
  })
}

*index.js

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,  // role์ด 0์ด๋ฉด ์ผ๋ฐ˜์œ ์ €, 0์ด ์•„๋‹ˆ๋ฉด ๊ด€๋ฆฌ์ž
    isAuth: true,
    email: req.user.email,
    name: req.user.name,
    lastname: req.user.lastname,
    role: req.user.rol,
    image: req.user.image
  })
})

๐ŸŸฃ๋กœ๊ทธ์•„์›ƒ ๊ธฐ๋Šฅ

๋กœ๊ทธ์•„์›ƒ Route ๋งŒ๋“ค๊ธฐ

๋กœ๊ทธ์•„์›ƒํ•˜๋ ค๋Š” ์œ ์ €๋ฅผ ๋ฐ์ดํ„ฐ ๋ฒ ์ด์Šค์—์„œ ์ฐพ์•„์„œ ๊ทธ ์œ ์ €์˜ ํ† ํฐ ์ง€์šฐ๊ธฐ

*index.js

app.get('/api/users/logout', auth, (req, res) => {
  User.findOneAndUpdate({_id: req.user._id},
    {token: ""} // token ์ง€์šฐ๊ธฐ
    ,(err, user) => {
      if(err) return res.json({ success: false, err});  // ์—๋Ÿฌ๋‚œ ๊ฒฝ์šฐ
      return res.status(200).send({ // ์„ฑ๊ณตํ•œ ๊ฒฝ์šฐ
        success: true
      })
    })
})

<loginํ–ˆ์„ ๊ฒฝ์šฐ token ์กด์žฌ>

<logoutํ–ˆ์„ ๊ฒฝ์šฐ token ์ง€์›Œ์ง>