회원가입 및 로그인 구현 #2

chu·2021년 4월 8일
1

로그인 및 회원가입 두번째 시간
노드로 구축한 백엔드 정리하려고 한다.


Node.js로 서버를 구축하기 위해서 프레임워크인 Express를 사용하였다.
DB는 MySQL이며, SQL문법 대신 자바스크립트 문법으로 대체할 수 있는 시퀄라이즈를 사용했다.

Express

전 글에서도 소개를 했었지만, 간단하게는 Node.js로 웹 서버를 구축할 수 있도록
여러 기능을 제공해주는 프레임워크다.

express install

npm i express

app.js

처음 작업 시 위 파일명으로 파일을 하나 만들어준다.

const express = require('express');

// express 객체를 app에 넣어준다.
const app = express();

// port라는 변수에 process.env.PORT || 3051 넣어준다.
app.set('port', process.env.PORT || 3051);

app.listen(app.get('port'), () => {
    console.log(app.get('port'), '번 포트애서 대기중');
});

위 코드는 정말 초기 세팅 중에서도 완전 초기 세팅이다.
process.env.PORT는 추후 배포 시 사용 되기 때문에 당장은 없어도 상관 없다.

그럼 작성된 코드를 모두 추가 해보겠다.

const express = require('express'); // express 가져오기
const session = require('express-session'); // 세션 관리를 위한 express-session
const morgan = require('morgan'); // 작업 수행 시 로깅
const cookieParser = require('cookie-parser'); // 쿠키 파싱 미들웨어
const cors = require('cors'); // CORS 에러 방지
const dotenv = require('dotenv'); // .env SECRET 정보 가져오기

// passportConfig - passport 내부 js 실행 (use, serialize, deserialze)
const passportConfig = require('./passport'); 
const passport = require('passport'); // passport 미들웨어 가져오기

// 위에는 모두 npm으로 설치를 해주세요.

// 제작한 모델 불러오기
const { sequelize } = require('./models/index');
// 라우터 불러오기
const pageRouter = require('./routes/page');
const userRouter = require('./routes/user');

// dotenv 실행
// dotenv를 통해 SECRET KEY를 받는 코드보다 위에 위치해야한다.
dotenv.config();

const app = express(); // app 변수에 express 객체 넣기.

sequelize.sync({ force: false }) // 이 코드 발견 시 시퀄라이즈 실행
.then(() => {
    console.log('데이터베이스 연결 성공');
})
.catch((err) => {
    console.error(err);
})

passportConfig();
app.set('port', process.env.PORT || 3051); // 포트 설정

app.use(morgan('dev')); // 개발모드로 로깅

app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(cors({
    origin: 'http://localhost:3000', // 단 아래 속성 true일 경우는 주소로 적어야한다.(보안강화)
    credentials: true, // front, back 간 쿠키 공유
}));

// cookieParser 설정에 비밀키를 넣어주자.
// cookieParser를 사용하게되면 req.cookies로 접근이 가능하다.
app.use(cookieParser(process.env.COOKIE_SECRET));

// session 설정
app.use(session({
    resave: false, // false 고정
    saveUninitialized: false, // false 고정
    secret: process.env.COOKIE_SECRET,
    cookie: {
        httpOnly: true, // 항상 true(자바스크립트로 진입 불가 - XXS 공격 방지)
    },
    // name의 기본값 - connect_sid
}));
// 아래 2개는 session 아래로 적어주자
app.use(passport.initialize()); // passport 초기화 미들웨어
app.use(passport.session()); // 앱에서 영구 로그인을 사용한다면 추가하자

// router
app.use('/', pageRouter); // /
app.use('/user', userRouter); // /user

// 404 처리 미들웨어
app.use((req, res, next) => {
    console.log('404 에러');
    res.status(404).send('Not Found');
});

// 에러 처리 미들웨어
app.use((err, req, res, next) => {
    console.error(err);
    res.status(err.status || 500).send(err.message);
});

app.listen(app.get('port'), () => {
    console.log(app.get('port'), '번 포트애서 대기중');
});

app.use(exrpess.json()) ?

마지막에 있는 json의 단어처럼 클라이언트에서 보내준 데이터를 json으로 파싱해서 req.body에
데이터를 넣어주는 역할을 합니다. 오래전에는 cookie-parser처럼 body-parser를 사용했다는데
현재는 express에서 제공해주는 미들웨어로 끝!

app.use(exrpess.urlencoded({ extended: true })) ?

로그인, 회원가입 등 form태그에서 submit하여 전달할 때 form 파싱해주는 역할을 합니다.

위 두가지는 필수로 장착하는 미들웨어라고 합니다!

추가적으로 이 작업을 통해서 cookiesession에 대해서 지식을 충분히 배우면
좋다고 생각이 듭니다. 이 회원가입과 로그인의 구현에서 중요한 역할을 해주는 요소이기 때문이죠.

간단하게 정리하자면,

cookie

브라우저에서 정보를 가지고 있는 파일이다. 쿠키에는 해킹에 위험이 되는 중요한 데이터는
담지 말아야한다. 쿠키는 브라우저에서 노출이 되고 있는 데이터기 때문이다.
물론 쿠키는 제한 되어있는 용량이 메가바이트 수준도 안되기 때문에 많은 데이터는 담아둘 수 없다.

그래서 팝업창의 다시보지 않기, 쇼핑몰에서는 장바구니 같은 중요하지 않는 데이터를
담아둘 때 쿠키를 사용한다.

팝업창의 다시보지 않기 같은 경우는 클릭할 시 쿠키에 다시 안본다는 데이터가 들어가게 되고,
새로고침하면 쿠키에 대한 정보를 읽고, 팝업창을 띄우지 않게 된다.

session

세션은 보통 유저가 로그인 후 페이지 이동 시 지속적으로 로그인을 유지할 수 있도록 사용하는데에
쓰인다. 클라이언트에서 로그인을 서버에 요청하면, 세션은 세션ID를 확인하고, 없으면 새로 생성하여
클라이언트측에 쿠키에 ID를 담아 보낸다. 그렇게 쿠키에 담긴 세션ID는 페이지를 이동하면서
인증서같은 역할을 한다. 그럼 페이지를 이동해도 로그인을 유지할 수 있게 된다.

  • 기본적으로 session은 메모리에 데이터가 할당되며, 옵션에 따라 데이터 저장소를 바꿀 수 있다.
  • 저장소에 유저의 정보를 갖고 있으며, 쿠키안에 세션의 정보는 단지 인증에 필요한 암호만 저장한 상태다.
  • 쿠키에 저장된 세션을 세션쿠키라고 불리며, 세션의 암호를 확인 후 일치하면 로그인 성공이 가능하다.
  • 서버에 접속할 때마다 브라우저는 세션쿠키를 서버로 보내고, 해당되는 세션ID의 대한 데이터를 조작할 수 있다.

정확한 흐름과 자세한 내용은 여기서 확인해보면 좋을 것 같다.

DB 구축

위에서 간단하게 로컬 서버를 구축을 했고, 이번에는 MySQL DB를 생성해본다.

install

npm i sequelize sequelize-cli mysql2

sequelize - 시퀄라이즈를 사용하기 위해 설치
sequelize-cli - 시퀄라이즈 명령어를 사용하기 위해 설치
mysql2 - MySQL과 노드를 연결시켜주기 위해 설치

설치 후 터미널에 아래처럼 입력하자

npx sequelize init

입력하게 되면, config, models, seeders,migrations 폴더 목록에 추가적으로 폴더가 설치된다.

config - config/config.js

const dotenv = require('dotenv');

// .env 파일의 DB_PASSWORD를 가져오기 위해
dotenv.config();

module.exports = {
  "development": { // 개발모드
    "username": "root", // 사용자 이름
    "password": process.env.DB_PASSWORD, // DB 비밀번호
    "database": "nodejs", // DB 이름
    "host": "127.0.0.1",
    "dialect": "mysql"
  },
  "test": { // 테스트
    "username": "root",
    "password": process.env.DB_PASSWORD,
    "database": "database_test",
    "host": "127.0.0.1",
    "dialect": "mysql"
  },
  "production": { // 배포용
    "username": "root",
    "password": process.env.DB_PASSWORD,
    "database": "database_production",
    "host": "127.0.0.1",
    "dialect": "mysql"
  }
}

user - models/user.js

모델은 DB의 테이블로 생각하면 된다. user는 유저에 대한 정보를 담는 테이블이다.

아래는 시퀄라이즈에서 모델을 init으로 정의하는 방법이다.
설정에 있는 type, allowNull의 소개는 생략하도록 하겠다.

const Sequelize = require('sequelize');

module.exports = class User extends Sequelize.Model {
  static init(sequelize) { // 테이블 설정
    return super.init({
      nick: {
        type: Sequelize.STRING(50),
        allowNull: true,
      },
      email: {
        type: Sequelize.STRING(50),
        allowNull: true,
        unique: true,
      },
      password: {
        type: Sequelize.STRING(100),
        allowNull: true,
      },
    },{
      sequelize,
      timestamps: true, // createAt, updateAt 자동 생성
      underscored: false, // sequelize에서 _ 사용할지 말지 ex) createAt -> create_at
      paranoid: true, // deleteAt을 생성 (삭제한 날짜)
      modelName: 'User', // modelName - javascript에서 쓰인다.
      tableName: 'users', // tableName - SQL에서 쓰이며, modelName의 소문자로 하고, 복수형으로 짓는다.
      charset: 'utf8',
      collate: 'utf8_general_ci',
    });
  }
};

이렇게 작성을 하면 User에 대한 테이블을 생성할 수 있다.

추가적으로 생성된 models의 폴더에는 기본 index.js가 있다.
그 내용 그대로는 안쓰고 수정해서 사용할 예정이다.

const Sequelize = require('sequelize');
const User = require('./user'); // 만든 User model

const env = process.env.NODE_ENV || 'development';
const config = require('../config/config')[env];
const db = {}; // db 빈 객체 생성

// new Sequelize(..options)로 DB와 연결
// config 파일에 만든 내용
const sequelize = new Sequelize(config.database, config.username, config.password, config);

db.sequelize = sequelize;

db.User = User;

User.init(sequelize);

module.exports = db;

이렇게 작성한 뒤 터미널에 명령어를 입력해주면 비로소 DB가 생성된다.

npx sequelize db:create

이번 시간에는 로컬서버 구축과 DB 생성에 대해서 정리를 하였고,

다음 시간에는 본격적으로 회원가입과 로그인에 필요한 라우터, 패스포트에 대해서
정리하겠다.

profile
한 걸음 한걸음 / 현재는 알고리즘 공부 중!

0개의 댓글