I T H

[MySchedule project] 5. backend - 회원가입 로직 본문

React + Node.js

[MySchedule project] 5. backend - 회원가입 로직

thdev 2024. 1. 25. 11:02
- 백앤드 : node.js  / mongoDB를 사용
- 백앤드 구조는 다음과같이 설정하였다.
데이터를 주고받는데에 효과적이고 중간에서의 매개역할과 같은 middleware 와 컬렉션(=테이블) 스키마를 관리하는 model, url경로를 효과적으로 관리하는 route로 설정함.

 

 

1. node.js의 환경을 만들어보자!

1) npm init

- npm init를 적게 되면 package.json파일이 뜰 것이다.

 

 

2) npm install express - save

 

- express를 다운로드 받자.

- espress는 node.js를 빠르고 편하게 사용할수 있게 도와주는 프레임워크임.

 

3) 전에 받아놨던 dependencies 라이브러리들이 있다면 복사 붙여넣기 해주자.

- 전에 했던 프로젝트들이 있다면 일일히 install 하기엔 시간이 오래걸리니 그대로 사용해주고 npm install을 쳐주자.

 

 

4) package.json 의 scripts에 시작을 할 부분을 넣어줌.

 

- "dev" : "nodemon src/index.js"
- 시작할때 npm run dev가 되는것임.

 

[index.js]

- 백앤드 (node.js) 환경에서 index.js 의 기본구조는 3가지로 나눌수 있다.

1) mongoose

- mongoose를 사용해서 mongodb에 연결하였다.

- mongoose : mongodb와 node.js를 위한 라이브러리로, 스키마를 편하게 만들수 있고 crud를 간편하게 사용할수있음.

 

2) 트랜잭션 설정

- startSession() : 세션을 생성함.

- startTransaction() : 트랜잭션 시작

- commitTransaction() : 앞의 작업들에 대한 commit 진행함.

- abortTransaction() : 실패시 트랜잭션 내 모든작업 rollback함.

- endSession() :  세션종료

 

3) route 설정

- index.js 페이지에 프론트앤드에서 보내준 데이터들을 모두 받고 처리하면 코드가 너무 길고 복잡해지므로, 

각 url에 맞게 나눌 것임.

- 아래의 코드는 '/register' url로 접근시 "./routes/register"로 타게 해주는 기능임.

ex) '/refigster' 일때와 '/register/idcheck' 둘다 아래와 같은 route를 타게 됨.

//route start
app.use("/register", require("./routes/register"));
//route end

 

const express = require("express");
const path = require("path");
const app = express();
const mongoose = require("mongoose");
const dotenv = require("dotenv");
const cors = require("cors");

//미들웨어 등록방법: app.use()를 사용하면됨.

//.env를 사용하기 위한 설정
dotenv.config();

// response 데이터를 받기위한 설정
app.use(express.json());

// 프론트와 백앤드의 포트가 다르기 때문에 cors를 통해서 연결해준다.
let corsOptions = {
  origin: "http://localhost:3000", //특정 도메인만 허용하기

  credentials: true,
};
//모두 허용
//app.use(cors());
app.use(cors(corsOptions));

// DB 설정 start
const port = 4003;
app.listen(port, () => {
  console.log(`${port}번에서 실행이 되었습니다.`);
});

const conn = mongoose // 몽고디비연결
  .connect(process.env.MONGODB_URI)
  .then(() => {
    console.log("연결완료");
  })
  .catch((err) => {
    console.error(err);
  });
// DB 설정 end

//트랜잭션 설정 start
const withTransaction = async (func) => {
  const session = await conn.startSession();

  session.startTransaction();

  try {
    await func(session);
    await session.commitTransaction();
    session.endSession();
  } catch (error) {
    await session.abortTransaction();
    session.endSession();
    throw error;
  }
};
//트랜잭션 설정 end

app.post("/", (req, res) => {
  console.log(req.body);
  res.json(req.body);
});
// express.static -> 정적 파일(이미지, css파일들)을 제공해줄수있게 해준다.
// path -> 절대경로로 어디서든지 사용할수있도록 해준다.
app.use(express.static(path.join(__dirname, "../uploads"))); //ex) http://localhost:4003/loginImage2.jpeg

// error 처리 미들웨어 start
app.get("/", (req, res, next) => {
  setImmediate(() => {
    next(new Error("error"));
  });
});
app.use((error, req, res, next) => {
  res.status(err.status || 500);
  res.send(error.message || "서버에러");
});
// error 처리 미들웨어 end

//route start
app.use("/register", require("./routes/register"));
//route end

 

[src / models / User.js]

const { default: mongoose } = require("mongoose");
const bcrypt = require("bcryptjs");
const userSchema = mongoose.Schema({
  userId: {
    type: String,
    maxLength: 20,
    unique: true,
    trim: true,
  },
  userName: {
    type: String,
    maxLength: 50,
  },
  userPhone: {
    type: String,
    maxLength: 30,
    trim: true,
  },
  userEmail: {
    type: String,
    trim: true,
  },
  userPassword: {
    type: String,
    minLength: 10,
  },
  userImage: {
    type: String,
    maxLength: 70,
  },
  role: {
    type: Number,
    default: 0,
  },
});

const User = mongoose.model("User", userSchema);

module.exports = User;

 

[src / routes / register.js]

1) 회원가입 - id 중복확인

- id 중복확인시 프론트에서 전달받은 id값으로 User컬렉션( = mysql의 테이블) 의 데이터를 찾고(findOne)

 찾은 값을 보내주는 로직이다.

 

2) 회원가입 -  회원등록

- 회원등록시 전달받은 값들을 save()메서드로 db에 저장한다.

- 여기서 그냥 저장하는것이 아닌 비밀번호 암호화를 먼저진행한 후  저장해야 하므로, models에 있는 User.js파일에 암호화 하는 부분을 넣어주어야된다.

const express = require("express");
const User = require("../models/User");
const router = express.Router();

//회원가입 - id중복확인
router.post("/idCheck", async (req, res, next) => {
  let userId = req.body.userId;
  console.log(userId);
  try {
    const userIdCheck = await User.findOne({ userId: userId });
    console.log(userIdCheck);

    return res.status(200).send(userIdCheck);
  } catch (error) {
    next(error);
  }
});

//회원가입 - 회원 등록
router.post("/", async (req, res, next) => {
  try {
    const user = new User(req.body);
    await user.save();
    return res.sendStatus(200);
  } catch (error) {
    next(error);
  }
});

module.exports = router;

 

[src / models / User.js] - 암호화 기능 코드 추가

1) 비밀번호 암호화 코드 추가

- salt : 사용자마다 같은 비밀번호가 있을수 있기에 salt로 비밀번호 앞에 추가로 넣어줌.

- hash: 평문->암호화하는 단방향 기법임.

- salt + hash의 조합을 만들어서 user스키마의 userPassword에 암호화된 값을 다시 넣어준다.

//pre : 몽고 디비에 저장하기 전에 호출되는 부분 - 스키마 생성 전에 호출되어야함.
userSchema.pre("save", async function (next) {
  let user = this;

  if (user.isModified("password")) {
    //password가 수정될때 실행
    const salt = await bcrypt.genSalt(10); //salt생성
    const hash = await bcrypt.hash(user.password, salt); //salt + hash의 조합을 할 거고, 보안을 위해 단방향(평문->암호화)인 hash를 사용한다.
    user.password = hash; //salt + hash로 암호화된 비번을 user의 password에 넣어줌.
  }

  next(); //다음단계로 넘어가기위해 사용
});

 

[ 결과화면 ]

 

role은 별도로 1을 주어 관리자로 만들었음.