[React JS] 1. Node.js

 

1.Node.js

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋ฅผ ํฌ๋กฌ์ด๋‚˜ IE๊ฐ€ ์•„๋‹Œ ์„œ๋ฒ„์‚ฌ์ด๋“œ์—์„œ๋„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ๋จ

java์™€ ๊ฐ™์ด ์„œ๋ฒ„์‚ฌ์ด๋“œ์—์„œ ์‚ฌ์šฉํ• ์ˆ˜์žˆ๋Š” javascript

 

Express JS?


2. boiler plate Project


3. Express.js 

npm install express --save
const express = require('express')
const app = express()
const port = 3000

app.get('/', (req, res) => {
  res.send('Hello World!')
})

app.listen(port, () => {
  console.log(`Example app listening on port ${port}`)
})
  "scripts": {
    "start": "node index.js",
    "test": "echo \"Error: no test specified\" && exit 1"
  }
npm run start

4. Mongo DB ์—ฐ๊ฒฐ

- mongoose ์„ค์น˜- mongodb ์—ฐ๊ฒฐ

const express = require('express')
const app = express()
const port = 3000

const mongoose = require('mongoose')
mongoose.connect('mongodb+srv://okol4561:password@first.2owuq.mongodb.net/?retryWrites=true&w=majority', {}).then(() => console.log('MongoDB Connected...')).catch(err => console.log(err))


app.get('/', (req, res) => {
  res.send('Hello World!')
})

app.listen(port, () => {
  console.log(`Example app listening on port ${port}`)
})

5. Model์ด๋ž€

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

- Schema : ์ •๋ณด๋“ค์„ ์ง€์ •

 

models ํด๋” ์ƒ์„ฑ

User.js ํŒŒ์ผ ์ƒ์„ฑ

 

const mongoose = require('mongoose');

const userSchema = mongoose.Schema({
    name: {
        type: String,
        maxlength: 50
    },
    email: {
        type: String,
        trim: true,
        unique: 1
    },
    password: {
        type: String,
        maxlength: 5
    },
    lastname: {
        type: String,
        maxlength: 50
    },
    role: {
        type: Number,
        default: 0
    },
    image: String,
    token: {
        type: String
    },
    tokenExp: {
        type: Numebr
    }
})

const User = mongoose.model('User', userSchema)
module.exports = { User }

6. BodyParser

- Client์™€ Server๊ฐ„ ํ†ต์‹ 

-> Request with Body (the JSON, buffer, String and URL encoded data)

-> body ๋ฐ์ดํ„ฐ๋ฅผ ๋ถ„์„(parse)ํ•ด์„œ req.body๋กœ ์ถœ๋ ฅํ•ด์ฃผ๋Š” ๊ฒƒ

-> body-parser dependency (์„œ๋ฒ„์—์„œ ํด๋ผ์ด์–ธํŠธ์˜ ์ •๋ณด๋ฅผ ๋ฐ›์„๋•Œ body parser dependency๋ฅผ ์ด์šฉ)

npm install body-parser --save

* client๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์— POSTMAN์„ ์‚ฌ์šฉํ•ด์„œ ๋ฐ์ดํ„ฐ ๋ณด๋‚ด๊ธฐ

 

-> Register Route๋งŒ๋“ค๊ธฐ

const  { User } = require("./models/User");
// ํด๋ผ์ด์–ธํŠธ์—์„œ ์˜ค๋Š” ์ •๋ณด๋ฅผ ์„œ๋ฒ„์—์„œ ๋ถ„์„ํ•ด์„œ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ๊ฒƒ
const bodyParser = require('body-parser');

// application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({extended: true}));

// applicaton/json
app.use(bodyParser.json());

app.post('/api/users/register',(req,res)=>{   
  //ํšŒ์›๊ฐ€์ž…ํ•  ๋•Œ ํ•„์š”ํ•œ ์ •๋ณด๋“ค์„ client์—์„œ ๊ฐ€์ ธ์˜ค๋ฉด,
  //๊ทธ ์ •๋ณด๋“ค์„ DB์— ๋„ฃ์–ด์ค€๋‹ค.
  const user = new User(req.body);
  //user๋ชจ๋ธ์— ์ •๋ณด๊ฐ€ ์ €์žฅ๋จ
  //์‹คํŒจ ์‹œ, ์‹คํŒจํ•œ ์ •๋ณด๋ฅผ ๋ณด๋‚ด์คŒ
  user.save().then(()=>{
      res.status(200).json({
          success:true
      })
  }).catch((err)=>{
      return res.json({success:false,err})
  });

})

7. Nodemon ๋‹ค์šด

npm install nodemon --save-dev

- ์„œ๋ฒ„๋ฅผ ๋„์ง€ ์•Š์•„๋„ ๋ฐ˜์˜์ด ๋˜๊ฒŒ๋”

 

nodemon์œผ๋กœ ์‹œ์ž‘ํ•˜๋Š” script ์ถ”๊ฐ€

"backend": "nodemon index.js",

8. Config ์„ค์ •

mongoURI ์ˆจ๊ธฐ๋Š” ์„ค์ • (gitignore)


9. Bcrypt ํŒจ์Šค์›Œ๋“œ ์•”ํ˜ธํ™”

npm install bcrypt --save

save ์ „์— ์•”ํ˜ธํ™”์‹œ์ผœ์ค˜์•ผํ•จ

(User.js์—์„œ)

 

saltRounds = salt๋ฅผ ์ด์šฉํ•ด์„œ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์•”ํ˜ธํ™” -> ์†”ํŠธ ์ƒ์„ฑ -> ์†”ํŠธ๋ฅผ ์ด์šฉํ•ด์„œ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์•”ํ˜ธํ™”

 

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

  // ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ๋ณ€๊ฒฝํ• ๋•Œ๋งŒ
  if (user.isModified("password")) {
    // ๋น„๋ฐ€๋ฒˆํ˜ธ ์•”ํ˜ธํ™”
    // salt ์ƒ์„ฑ
    bcrypt.genSalt(saltRounds, function (err, salt) {
      if (err) return next(err);

      //๋น„๋ฐ€๋ฒˆํ˜ธ ์ƒ์„ฑ๋๋‹ค๋ฉด
      bcrypt.hash(user.password, salt, function (err, hash) {
        if (err) return next(err);

        //์•”ํ˜ธํ™” ์„ฑ๊ณต๋˜๋ฉด hash๋œ ๋น„๋ฐ€๋ฒˆํ˜ธ๋กœ ๋ณ€๊ฒฝ
        user.password = hash;
        next();
      });
    });
  }else{
    next()
  }
});

10. ๋กœ๊ทธ์ธ

ํ† ํฐ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•œ jsonwebtoken ์„ค์น˜

npm install jsonwebtoken --save

์ฟ ํ‚ค์— ํ† ํฐ ์ €์žฅ์œ„ํ•œ cookie-parser ์„ค์น˜

npm install cookie-parser --save

 

๋กœ๊ทธ์ธ

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: "์—†๋Š” ์•„์ด๋””์ž…๋‹ˆ๋‹ค.",
        });
      }

      // ์š”์ฒญ๋œ ์ด๋ฉ”์ผ์ด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์žˆ๋‹ค๋ฉด, ๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ์ผ์น˜ํ•˜๋Š”์ง€ ํ™•์ธ
      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 });
        });
      });
    })
    .catch((err) => {
      return res.status(400).send(err);
    });
});

 

User.js

userSchema.methods.comparePassword = function (plainPassword, cb) {
  // ๋น„๋ฐ€๋ฒˆํ˜ธ ๋น„๊ต
  bcrypt.compare(plainPassword, this.password, function (err, isMatch) {
    if (err) return cb(err);
    //์—๋Ÿฌ๋Š” ์—†๊ณ  ๋งž์œผ๋ฉด isMatch true
    cb(null, isMatch);
  });
};

userSchema.methods.generateToken = function (cb) {
  var user = this;

  var token = jwt.sign(user._id.toHexString(), "secretToken");
  user.token = token;
  /*
  user.save(function (err, user) {
    if (err) return cb(err);
    cb;
  });
  */
  user
    .save()
    .then((user) => {
      cb(null, user);
    })
    .catch((err) => {
      return cb(err);
    });
};

11. Auth ๊ธฐ๋Šฅ ๋งŒ๋“ค๊ธฐ

ํ† ํฐ์„ ๋งŒ๋“  ํ›„ ์œ ์ €์ •๋ณด(์„œ๋ฒ„)์™€ ์ฟ ํ‚ค(๋ธŒ๋ผ์šฐ์ €)์— ๋„ฃ์–ด์คŒ

๋‘๊ฐ€์ง€ ํ† ํฐ์ด ์„œ๋กœ ๋งž๋Š”์ง€ ์ง€์†์ ์œผ๋กœ ์ฒดํฌ

-> ์–ด๋–ป๊ฒŒ ํ•˜๋ƒ? ์‹œํฌ๋ฆฟ ํ† ํฐ์„ ๋„ฃ์œผ๋ฉด ์œ ์ € ์•„์ด๋””๊ฐ€ ๋‚˜์˜ค๋Š”๋ฐ ๊ทธ ์•„์ด๋””๋ฅผ db์—์„œ ์ฐพ์•„์„œ ํ•ด๋‹น ์œ ์ €์˜ ํ† ํฐ์„ ํ™•์ธ

 

*get์š”์ฒญ ๋ฐ›์„ ๋•Œ middle ware 'auth' ์ถ”๊ฐ€

๋ฏธ๋“ค์›จ์–ด๋ž€? : ์—”๋“œํฌ์ธํŠธ์—์„œ req๋ฐ›์€ ํ›„ ์ฝœ๋ฐฑํŽ‘์…˜ ํ•˜๊ธฐ์ „์— ์ค‘๊ฐ„์—์„œ ํ•ด์ฃผ๋Š” ๊ฒƒ

 

index.js

app.get("/api/users/auth", auth, (req, res) => {
  // ์—ฌ๊ธฐ ์™”๋‹ค๋Š” ๊ฑด auth ํ†ต๊ณผํ–ˆ๋‹ค๋Š” ์˜๋ฏธ
  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, 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();
  });
};

module.exports = { auth };

User.js

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

  // ํ† ํฐ์„ decode
  jwt.verify(token, "secretToken", function (err, decoded) {
    // ์œ ์ €์•„์ด๋””๋ฅผ ์ด์šฉํ•ด์„œ ์œ ์ €๋ฅผ ์ฐพ์€ ํ›„ ํด๋ผ์ด์–ธํŠธ token๊ณผ db ํ† ํฐ ์ผ์น˜ ์—ฌ๋ถ€ ํ™•์ธ
    user
      .findOne({ _id: decoded, token: token })
      .then((user) => {
        cb(null, user);
      })
      .catch((err) => {
        return cb(err);
      });
  });
};

12. ๋กœ๊ทธ์•„์›ƒ ๊ธฐ๋Šฅ ๋งŒ๋“ค๊ธฐ

๋กœ๊ทธ์•„์›ƒํ•˜๋ ค๋Š” ์œ ์ €๋ฅผ ์•„์ด๋””๋กœ ์ฐพ์•„์„œ ํ•ด๋‹น ์œ ์ €์˜ ํ† ํฐ์„ ์ง€์›Œ์ฃผ๋ฉด๋จ

์•„์ด๋”” ๊ฐ€์ ธ์˜ค๋Š” ๋ฒ•์€ auth๋ฅผ ๊ฑฐ์น˜๊ธฐ ๋•Œ๋ฌธ์— ๋‚ด๊ฐ€ ๊ฐ€์ง„ ๋ธŒ๋ผ์šฐ์ € ์ฟ ํ‚ค์˜ ํ† ํฐ์œผ๋กœ ์ฐพ์€ user์ •๋ณด๊ฐ€ req์— ๋‹ด๊ฒจ์„œ ๋„˜์–ด์˜ด

 

index.js

app.get("/api/users/logout", auth, (req, res) => {
  User.findOneAndUpdate({ _id: req.user._id }, { token: "" })
    .then((user) => {
      return res.status(200).send({ success: true });
    })
    .catch((err) => {
      return res.json({ success: false, err });
    });
});
  • ๋„ค์ด๋ฒ„ ๋ธ”๋Ÿฌ๊ทธ ๊ณต์œ ํ•˜๊ธฐ
  • ๋„ค์ด๋ฒ„ ๋ฐด๋“œ์— ๊ณต์œ ํ•˜๊ธฐ
  • ํŽ˜์ด์Šค๋ถ ๊ณต์œ ํ•˜๊ธฐ
  • ์นด์นด์˜ค์Šคํ† ๋ฆฌ ๊ณต์œ ํ•˜๊ธฐ