본문 바로가기

Backend/Project

[ToDoList_Project] 3월 1주차 - 로그인, 로그아웃, 회원가입 기능 구현

www.notion.so/3-1-930e8d825c0c44b4a77f4fa466f60dca

 

3월 1주차 - 로그인/회원가입 기능구현

app과 서버를 연결

www.notion.so

app과 서버를 연결

app : express 모듈을 실행해 app 변수에 할당한다. express 내부에 http 모듈이 내장되어 있으므로 서버의 역할을 할 수 있다.

const express = require('express') //다운받은 express 모듈 가져오기
const app = express()
//express 내부에 http모듈이 내장되어 있으므로 서버의 역할을 할 수 있다.
//모듈을 통해서 객체를 만들어준다.
//-> 모듈은 함수라서 app을 리턴한다. 
const port = 5000 //5000 port를 backserver로 둔다.

//몽구스를 이용해서 app과 서버를 연결할 것!
const mongoose = require('mongoose');
mongoose.connect(config.mongoURI, {
    useNewUrlParser: true, useUnifiedTopology: true, useCreateIndex: true, useFindAndModify: false
}).then(() => console.log('MongoDB Connected...'))
.catch(err => console.log(err))

app.get('/', (req, res) => res.send('Hello World!'))
//route 디렉토리에 오면 Hello World!를 출력되게 한다.


app.listen(
    port, () => console.log(`Example app listening on port ${port}!`)
)
//이 app이 5000번에 listen을 하면 console에  출력된다.

<index.js>

  • app.get(주소, 라우터)

    : 주소에 대한 GET요청이 올 때 어떤 동작을 할지 적는 부분이다. req는 요청에 관한 정보, res는 응답에 관한 정보가 들어있다.

    위 코드는 GET / 요청 시 응답으로 Hello World!를 전송한다.

  • app.listen(포트 명, 리스닝 성공했을 때 실행될 콜백함수)

    : 포트를 연결하고 서버를 실행한다.

User Schema

유저 모델 생성

회원가입을 할 때, 발생하는 유저 데이터들은 유저 데이터베이스에 들어가게 된다.

유저와 관련된 데이터들을 보관하기 위해서 유저모델(유저 스키마)를 만들어야 한다.

모델은 스키마를 감싸고 스키마는 하나하나의 정보를 지정해 줄 수 있다.

//유저 모델과 스키마 만들기
const mongoose = require('mongoose'); //몽구스 모델 가져오기

//유저 스키마를 만든다!
const userSchema = mongoose.Schema({
    nickName: {
        type: String,
        minlength: 2,
        maxlength: 10,
        required: true,
        trim: true,
        unique: 1
    },
    id: {
        type: String,
        trim: true,
        minlength: 5,
        maxlength: 10,
        required: true,
        unique: 1
    },
    password: {
        type: String,
        minlength: 5,
        required: true
    },
    role: {
        //관리자 유저 혹은 일반 유저일 수도 있기에 role을 부여한다.
        type: Number,
        default: 0
    },
    image: String,
    token: {
        //토큰을 할당해서 유효성을 검사할 수 있다.
        type: String
    },
    tokenExp: {
        //토큰을 사용할 수 있는 기간을 부여한다.
        type: Number
    }
})

// 스키마를 모델로 변환하여 내보내기 합니다.
const User = mongoose.model('User', userSchema) // (이 모델의 이름, 스키마 이름)
module.exports = {User} //다른 곳에서도 이 모델이 쓰일 수 있게 export 해준다.

<User.js>

회원가입 기능

Client에서 정보들을 받아서 Server로 넘겨준다.

이때 정보를 받으려고 할 때, 필요한 기능이 body-parser 이다.

Body데이터를 분석(parse)해서 req.body로 출력해주는 것!

  • body-parser 란?

    npm install body-parser —save (설치)

    요청(req)의 본문에 있는 데이터를 해석하여 req.body로 만들어주는 미들웨어이다. 보통 폼 데이터나 AJAX 요청의 데이터를 처리한다.

    JSON은 JSON 형식의 데이터 전달 방식이고, URL-encoded는 주소 형식으로 데이터를 보내는 방식이다.

     

const bodyParser = require('body-parser');
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true})); //qs모듈을 사용하여 쿼리스트링을 해석한다.
const bodyParser = require('body-parser');
const { User } = require('./models/User'); // 회원가입할 때, 필요해서 User모델을 가져온다.

//register Route
app.post('/register', (req, res) => { //(endpoint, 콜백함수)
    //회원가입 할 때, 필요한 정보들을 client에서 가져오면
    //그것들을 데이터 베이스에 넣어준다.
    //이것들을 하기 위해서 User 모델을 가져와야 한다.
    const user = new User(req.body)

    //이 사이에 비밀번호를 암호화 시켜야 한다.

    //받아온 정보들이 User모델에 저장됨 .save는 
    user.save((err, userInfo) => {
        if(err) return res.json({ success: false, err})
        return res.status(200).json({
            success: true
        })
    })
})

<index.js>

 

  • req.body : body-parser 미들웨어가 만드는 요청의 본문을 해석한 객체이다.

또, Client에서 Requset를 줘야 하는데 현재 Client가 없기에 postman을 이용해서 request를 보낸다. 

 

비밀번호 암호화

bcrypt를 이용하여 비밀 번호를 암호화 해줘서 데이터 베이스에 저장해야한다.

  • npm install bcrypt —save

유저 정보를 데이터 베이스에 저장하기 전에가 암호화 될 타이밍이다.

bcrypt사이트 보면서 진행하면 된다. (https://www.npmjs.com/package/bcrypt) ⇒ Usage에 Technique 1을 보면된다.

이 때, salt를 사용한다.

const bcrypt = require('bcrypt'); //비밀번호를 암호화할 때, 필요한 bcrypt 가져오기 
const saltRounds = 10; //salt가 몇 글자인지를 나타낸다.

userSchema.pre('save', function(next){
    var user = this; //userSchema를 가리킴
    if(user.isModified('password')) { //비밀번호가 변경될 때만 bcrypt를 이용해서 암호화하도록 설정한다.
        //비밀번호를 암호화 시킨다.
        bcrypt.genSalt(saltRounds, function(err, salt) {
            if(err) return next(err);

            bcrypt.hash(user.password, salt, function(err, hash) {
								//hash는 암호화된 비밀번호이다.
                if(err) return next(err);
                user.password = hash;
                next();
            });
        });
    } else { //비밀번호가 아닌 다른 걸 바꿀땐, 
        next()
    }
})

<User.js>

  • userSchema.pre('save', function(next) {

    next();

    })

    : register Route에서 User 모델에 유저정보들을 저장하기 전에 function을 실행시킨다. function 안에 내용들이 끝난 후, next()로 다음 실행을 할 수있도록 한다.

  • salt, saltRounds

    : salt를 이용해서 비밀번호를 암호화한다. 이때, salt를 사용하려면 salt를 생성해야 한다. saltRounds는 salt가 몇 글자인지를 나타낸다.

  • genSalt(rounds, callback)

    : 이 메소드를 이용해 salt값을 생성한다.

  • isModified 함수

    : 해당 값이 db에 기록된 값과 비교해서 변경된 경우 true를 그렇지 않은 경우 false를 반환해주는 함수이다.

비밀 설정 정보 관리

예를 들어 mongoDB를 연결할 때, secret한 정보들이 있다. 이러한 정보들을 한 파일에 넣고 .gitignore 파일에 넣어주어야 한다.

index.js에서 key.js 파일을 불러와서 사용하니까 module.exports를 쓰고, dev.js랑 prod.js 파일을 따로 만들었기 때문에 require를 사용했다.

if(process.env.NODE_ENV === 'production') {
    module.exports = require('./prod');
} else{
    module.exports = require('./dev');
}

<key.js>