카테고리 없음

Node.js | 로그인, 회원가입

JOOHUUN 2022. 8. 19. 21:07
$ npm init // package.json 파일 생성
$ npm install express --save
$ npm install mongoose --save // 몽고디비툴 설치
$ npm install nodemon --save-dev // node에서 liveserver 역할하는 툴

폴더 구조

1. package.json 

{
  "name": "youtube",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "node index.js",
    "backend": "nodemon index.js",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "bcrypt": "^5.0.1",
    "body-parser": "^1.20.0",
    "cookie-parser": "^1.4.6",
    "express": "^4.18.1",
    "jsonwebtoken": "^8.5.1",
    "mongoose": "^6.5.2"
  },
  "devDependencies": {
    "nodemon": "^2.0.19" 
  }
}

2. index.js

- api 작성

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

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

// application/json
app.use(bodyParser.json());
app.use(cookieParser());

// 몽고디비 연동
mongoose.connect(config.mongoURI, {
    useNewUrlParser: true,
    useUnifiedTopology: true,
}).then(() => console.log('MongDB Connected...!'))
 .catch(err => console.log(err))


app.get('/', (req, res) => {
  res.send('안녕하세요!!')
})

// 회원가입
app.post('/register', (req, res) => {
    // req.body 안에는 json형식의 데이터가 들어 있음
    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) => {
    // 요청된 Email을 DB에 있는지 찾기
    User.findOne({email: req.body.email}, (err, user) => {
        if (!user) {
            return res.json({loginSuccess: false, 
                message: "일치하는 유저가 없습니다."
            });
        }
        // 요청된 이메일이 DB에 있다면 비밀번호가 일치한지 확인.
        user.comparePassword(req.body.password, (err, isMatch) => {
            if (!isMatch) 
               return res.json({loginSuccess: false, 
                message: "비밀번호가 틀렸습니다."
            });
            console.log(isMatch)
            // 비밀번호 까지 맞다면 token 생성
            user.generateToken((err, user) => {
                if (err) return res.status(400).send(err);
                // 토큰저장(로컬or쿠키)
                res.cookie("x_auth", user.token)
                .status(200)
                .json({loginSuccess: true, userId: user._id});
            });              
        });
    });  
});


app.listen(port, () => {
  console.log(`Example app listening on port ${port}`)
})
// 몽고디비 연동
mongoose.connect(config.mongoURI, {
    useNewUrlParser: true,
    useUnifiedTopology: true,
}).then(() => console.log('MongDB Connected...!'))
 .catch(err => console.log(err))
// config/dev.js
module.exports = {
    mongoURI:'mongodb+srv://kimjuhoon:<password>@cluster0.4l2nw.mongodb.net/?retryWrites=true&w=majority'
}

mogoose에서 제공하는 connect함수를 사용해서 몽고디비와 연결

config.mongoURI는 config/dev.js 위치에 몽고디비키 입력

// 회원가입
app.post('/register', (req, res) => {
    // req.body 안에는 json형식의 데이터가 들어 있음
    const user = new User(req.body);
    user.save((err) => {
        if (err) return res.json({success: false, err});
        return res.status(200).json({success: true});
    });
});

const user = new User(req.body);

json형식의 데이터로 되어 있는 사용자가 요청한(reqeust) 값을 user라는 변수로 만듬

유효성 검증이 통과하지 못하면면 success: false, 그렇지 않으면 success: true

// 로그인
app.post('/login', (req, res) => {
    // 요청된 Email을 DB에 있는지 찾기
    User.findOne({email: req.body.email}, (err, user) => {
        if (!user) {
            return res.json({loginSuccess: false, 
                message: "일치하는 유저가 없습니다."
            });
        }
        // 요청된 이메일이 DB에 있다면 비밀번호가 일치한지 확인.
        user.comparePassword(req.body.password, (err, isMatch) => {
            if (!isMatch) 
               return res.json({loginSuccess: false, 
                message: "비밀번호가 틀렸습니다."
            });
            console.log(isMatch)
            // 비밀번호 까지 맞다면 token 생성
            user.generateToken((err, user) => {
                if (err) return res.status(400).send(err);
                // 토큰저장(로컬or쿠키)
                res.cookie("x_auth", user.token)
                .status(200)
                .json({loginSuccess: true, userId: user._id});
            });              
        });
    });  
});

User.findOne({email: req.body.email}, (err, user) => {}

findeOne은 몽고디비에서 한개의 객체를 찾을 때 사용하는 함수이다

사용자가 요청한 email값이 디비에 있는지 확인 한 후 아래 코드 실행

비밀 번호가 일치 하는지 검사하는 comparePassword, 로그인 성공시 토큰을 생성하는 generateToken 함수는 User.js에서 작성하고 여기서는 간단한 로직만 작성한다.

3. 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: 3    
    },
    lastname: {
        type: String,
        maxlength: 50
    },
    role: {
        type: Number,
        default: 0
    },
    image: String,
    token: {
        type: String,
    },
    tokenExp: {
        type: Number
    }
})

// 유저 모델의 유저정보를 저장하기 전에 실행함
userSchema.pre('save', function(next) {
    // userSchema를 가리키는 변수 생성
    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();
    }
});

userSchema.methods.comparePassword = function(plainPassword, cb) {
    var user = this;
    // plainpassword = 해싱안된 암호 
    bcrypt.compare(plainPassword, user.password, function(err, isMatch) {
        if (err) return cb(err, isMatch);
        cb(null, isMatch);
    });
};


userSchema.methods.generateToken = function (cb) {
    var user = this;
    // jsonwebtoken 이용하여 토큰 생성
    // user._id + 'secretToken' = token
    // 'secretToken'을 디코딩하면 user._id
    var 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};