프로젝트 1 - 로그인 기능

⭐프로젝트 1 - 로그인 기능

📕로그인 기능

우선 로그인 라우터가 필요하다

이 로그인 라우터에서 해야할 일은 3가지가 있다

  1. DB에서 요청한 이메일 찾기

  2. DB에서 요청한 이메일이 있다면 비밀번호가 같은지 확인하기

  3. 비밀번호까지 같다면 토큰 생성하기

    `app.post('/login', (req, res) => { 여기 }`

    위 코드를 index.js에 작성하고

여기 안에 아래 3가지 코드를 각각 추가하면 된다

📗DB에서 요청한 이메일 찾기

DB에서 찾기위해서 우선 유저 모델을 가져온다

이후 몽고DB에서 제공하는 메소드인 .findOne() 을 사용한다

그리고 해당하는 유저가 없다면 로그인이 실패했다고 JSON으로 리턴하자

app.post('./login', (req, res) => {
  User.findOne({ email: req.body.email }, (err, user) => {
    if(!user) {
      return res.json({
        loginSuccess: false,
        message: "해당 이메일에 해당하는 유저가 없습니다."
      })
    }
  })
}

유저가 있다면 아래 기능으로 넘어간다

📘비밀번호가 같은지 확인하기

지금 우리가 비밀번호를 저장할 때 Bcrypt로 암호화를 해서 저장한다

단방향으로만 진행되기 때문에 암호화된 암호를 복호화할 수 없다

그래서 사용자가 입력칸에 친 plainPassword가 DB에 있는 비밀번호와 같은지

비교하기 위해서는 plainPassword를 암호화 한 후에 비교를 해야한다

그래서 bcrypt.compare 을 사용할 것이다

그러기 위해서 comparePassword라는 메소드를 만들어야 한다

인자로는 req.body.password로 plainPassword하나를 넣고,

두번째로는 콜백 함수를 넣을 것이다

콜백은 에러가 났을 경우 리턴할 err과 암호화된 비밀번호와 순수한 비밀번호가

맞는지 아닌지를 알려주는 isMatch를 넣을 것이다

isMatch는 true, false로 리턴된다

User.js에서 메소드를 먼저 만들자

userSchema.methods.comparePassword = function(plainPassword, cb) {
    bcrypt.compare(plainPassword, this.password, function(err, isMatch) {
        if(err) return cb(err)
        cb(null, isMatch)
    })
}

이렇게 작성을 하고 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: "비밀번호가 틀렸습니다."
        })
      }
    })
  })
})

만약 isMatch가 true가 아니라면 로그인이 실패한 것이고, 실패했다고 리턴하면 된다

📙비밀번호가 같다면 토큰 생성하기

토큰 생성을 위해서 JSONWEBTOKEN 라이브러리를 다운받아야 한다

npm install jsonwebtoken --save

위에서 메소드를 만든 것 처럼 토큰을 발행하는 메소드를 따로 만들어야 한다

그리고 메소드를 만드는 과정은 사이트를 확인하면 과정이 잘 나와있다

사이트를 참조하면서 User.js에 메소드를 만들어보자

userSchema.methods.generateToken = function(cb){
    let user = this
    let token = jwt.sign(user._id.toHexString(), 'secretToken');

    user.token = token
    user.save(function(err, user){
        if(err) return cb(err)
        cb(null, user)
    })
}

user._id 와 secretToken을 합치면 token을 만드는 것이다

token을 해석을 할 때 secretToken을 넣으면 user._id가 나오게 된다

token을 user에 넣어서 리턴하자

이제 위의 메소드를 index.js에서 사용해야 한다

index.js에서 사용하는 과정은 아래와 같다

만약 에러가 리턴 됐다면 status(400)을 리턴하는거고 이건 오류를 의미한다

그리고 토큰을 저장해야하는데 쿠키, 로컬스토리지등등 저장할 수 있다

우리는 쿠키에 저장하도록 하자

쿠키에 저장하려면 라이브러리를 하나 다운받아야 하는데 바디파서처럼

쿠키파서라는 라이브러리를 다운받아야한다

npm install cookie-parser --save

그리고 상단에 const cookieParser = require('cookie-parser')와

app.use(cookieParser())을 추가하자

그리고 쿠키를 이용해서 토큰을 저장하자

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.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
        })
      })
    })
  })
})

지난 강에서 [email protected]이랑 1234abcd로 회원가입을 했다

이걸 사용해서 postman에서 로그인을 해보자

http://localhost:3000/login으로 포스트 메소드로 세팅해놓자

이후 body에 raw, JSON으로 선택하고 여기에 정보를 입력하면 된다

{
	"email": "[email protected]",
    "password": "1234abcd"
}

이렇게 해서 send를 해보자

그러면 제대로 JSON이 나오는 것을 볼 수있다

코드가 헷갈릴 수 있어서 전문을 넣도록 하겠다

📔코드

index.js

const express = require('express')
const app = express()
const port = 3000
const mongoose = require('mongoose')
const { User } = require("./models/User")
const bodyParser = require('body-parser')
const config = require('./config/key')
const cookieParser = require('cookie-parser')

app.use(bodyParser.urlencoded({extended: true}))
app.use(bodyParser.json())
app.use(cookieParser())

mongoose.connect(config.mongoURI
).then( () => console.log('MongoDB Connected'))
 .catch(err => console.log(err))

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

app.post('/signup', (req, res) => {
  //회원 가입 할 때 작성한 정보들을 가져와 DB에 넣어준다
  const user = new User(req.body)

  user.save((err, userInfo) => {
    if (err) return res.json({ success: false, err})
    return res.status(200).json({
      success: true
    })
  })
})

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.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
        })
      })
    })
  })
})

app.listen(port, () => {
  console.log(`http://localhost:${port}/`)
})

user.js

const mongoose = require('mongoose')
const bcrypt = require('bcrypt')
const saltRounds = 10
const jwt = require('jsonwebtoken')

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

userSchema.pre('save', function(next){
    let 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()
    }
})

userSchema.methods.comparePassword = function(plainPassword, cb) {
    bcrypt.compare(plainPassword, this.password, function(err, isMatch) {
        if(err) return cb(err)
        cb(null, isMatch)
    })
}

userSchema.methods.generateToken = function(cb){
    let user = this
    let token = jwt.sign(user._id.toHexString(), 'secretToken');

    user.token = token
    user.save(function(err, user){
        if(err) return cb(err)
        cb(null, user)
    })
}

const User = mongoose.model('User', userSchema)

module.exports = { User }

좋은 웹페이지 즐겨찾기