Boiler-plate: Sign-up & Log-in and out

Janet·2022년 10월 4일
0

Web Development

목록 보기
2/13

  • Git-hub Link: https://github.com/Jiyaho/boiler-plate
  • Node.js와 Express.js, mongoDB와 POSTMAN APP을 통해 Boiler-plate를 구현해보고, React를 통해 front부분을 추가하였다. 그리고 Redux를 통해 상태 관리.
  • 본 내용은 Youtube - John Ahn님의 노드 리액트 기초 강의를 듣고 정리한 내용들 입니다.

📕 Boiler-plate: Sign-up & Log-in and out

  • Boiler-plate은 사전적 의미로는 말그대로 보일러의 판 그리고 표준 문구라는 뜻을 가지고 있는데 이는 보일러의 기초 골격을 찍어내는 판이다. 또한 한때 신문사에서도 이러한 방법을 신문을 만드는 데에도 활용하였는데 잘 바뀌지 않는 기본 내용과 구조들을 철판으로 만들어 찍어내는 방식으로 신문 인쇄의 방법으로 썼다고 한다. 따라서 계속 반복해서 만들어내야 하는 기본 구조를 판으로 만들어두고 나머지 그때마다 필요한 부분들만 추가하여 완제품을 보다 효율적으로 만들 수 있는 것이다.
  • 웹 개발에 있어서도 반복적으로 필요로 하는 기본적인 기능들이 있는데, 예를 들어 웹페이지에서 사용자가 회원가입을 하고 로그인을 하는 등의 기능 또한 그러하다. 여기서는 회원가입과 로그인, 로그아웃 기능을 구현한 Boiler-plate이다.
  • 백엔드 부분을 배우기위해 입문 강의로 John Ahn님의 Node.js & React 강의를 수강하였다.
  • React.js로 개발, 상태 관리 라이브러리는 Redux를 사용하였고, 서버는 Node.js, 데이터베이스는 MongoDB를 사용하였다.

🔶 BACK-END ( Server )

🔸 node.js

:자바스크립트를 서버사이드에서 쓸 수 있는 언어라고 보면 된다.
자동차의 엔진과 같은 역할

🔸 Express.js

:node js를 좀 더 쉽게 이용할 수 있게 도와주는 프레임워크라고 할 수 있다.
자동차의 바퀴나 부속품 등을 만들어 주는 역할


🔸 Node.js 및 Express.js 설치

  • node.js 설치 후 프로젝트 폴더 생성
  • npm init 터미널 입력하여 프로젝트 폴더 안에 package.json 파일 생성
    - server 폴더 생성 및 하위 파일로 index.js 생성(서버 관련 main file)
    - express 설치: npm install express --save
    - (Cf. 패키지, 라이브러리 등을 설치할 때, 끝에 명령어 --save 를 붙이면 package.json에서 dependencies 목록에 다운받은 패키지명과 버전이 자동으로 저장됨.)

🔸 Express 기본 템플릿 붙여넣기

  • Index.js에 express 아래 기본 템플릿을 붙여넣고, 서버의 포트번호는 5000으로 해주었다.
const express = require("express");
const app = express();
const port = 5000;

app.get("/", (req, res) => res.send("Hello World!"));

app.listen(port, () => console.log(`Example app listening on port ${port}!`));
  • package.json에 scirpts를 추가 해준다. "start": "node server/index.js",
  • npm run start로 서버 실행
  • 포트번호 url로 웹브라우저 접속: localhost/5000

🔸 MongoDB 가입 후 Cluster 생성

  1. Cluster 를 생성하는데, 먼저 Project 생성하고 Build a Database 한다.
  2. Database는 Free로 제공하는 Shared를 선택.
  3. Cloud Provider: aws
  4. 서비스 생성 지역: Free Tier로 제공하는 곳 중 한국과 가까운 곳 아무곳이나해도 되는데, Seoul도 Free Tier라서 서울로 설정했다.
  5. Cluster Tier: Free로 제공하는 M0 Sandbox 선택
  6. Cluster Name 입력 후 Cluster 생성
  7. 정상적으로 생성되었다면 Connect를 눌러 mongoDB User를 생성해준다. Password는 특수문자 없이 만들고, Username과 Password는 코딩 시 입력해야 하기때문에 기억해 둘 것.
  8. Connection method는 Connect Your Application 선택.
  9. Connection String Only의 코드를 복사한다.

🔸 Mongoose 설치

  • Mongoose는 mongoDB를 보다 편하게 쓸 수 있게 도와주는 Object Modeling Tool이다.
    - 설치: npm install mongoose --save
const mongoose = require("mongoose");
mongoose.connect("몽고DB 컨넥션 코드")
	.then(() => console.log("mongoDB Connected.."))
	.catch(err => console.log(err));
// connection code에 <password>부분은 본인의 password를 넣어준다.
// console.log 찍어주는 이유는 몽고DB가 정상적으로 연결되었는지 확인하기 위함.

🔸 Model과 Schema 생성하기

  • 유저의 로그인 관련 데이터를 보관하기 위해 user model & user schema를 만든다.
  • Model이란 Schema를 감싸주는 역할을 함.
  • Schema란? 입력할 데이터들의 type(String, Number 등)은 무엇인지, maxlength를 정하여 몇글자까지 할 것인지 등의 입력할 값들의 규칙과 양식을 지정해두는 것.
  • server 폴더 > models 폴더 > User.js에 user model 입력
// User.js

const mongoose = require("mongoose");

const userSchema = mongoose.Schema({
  name: {
    type: String,
    maxlength: 50,
  },
  email: {
    type: String,
    trim: true, // trim: 유저가 입력한 스페이스 빈 공간을 없애주는 코드
    unique: 1, // 여러 유저가 중복된 이메일주소를 쓸 수 없게끔하는 코드
  },
  password: {
    type: String,
    // maxlength: 5,
  },
  lastname: {
    type: String,
    maxlength: 50,
  },
  role: {
    // 사용자 권한을 분류
    type: Number,
    default: 0, // 사용자 권한 디폴트값
  },
  image: String,
  token: {
    // 유효성 관리
    type: String,
  },
  tokenExp: {
    // 토큰 유효기간
    type: Number,
  },
});


const User = mongoose.model("User", userSchema); 
// Model로 Schema를 감싸준다.

module.exports = { User }; // 다른 컴포넌트에서도 쓸 수 있도록 export


🔸 Client의 Request를 Server로 보내기 위한 라이브러리 및 앱 설치: Body-parser & POSTMAN

  1. 유저가 클라이언트에 입력한 로그인 데이터, 해당 request를 서버로 보내기위해 Body-parser Dependency를 이용할 것

    • Body-parser Dependency란? Body 데이터를 분석(parse)해서 req.body로 출력해 주는 것
    • 설치: npm install body-parser --save
    • Index.js에 설치한 body-parser를 가져오고 아래 코드 입력.

    ✅ cf. 업데이트된 사항!

    • express에 기본적으로 포함되어 body-parser 설치할 필요 없음
// index.js 
// 업데이트 전 코드!!
	
const bodyParser = require("body-parser");
	
//"application/x-www-form-urlencoded" 형식의 데이터를 parse해 줌
app.use(bodyParser.urlencoded({ extended: true }));
	
//"application/json" 형식의 데이터를 parse해 줌
app.use(bodyParser.json());

// 업데이트 후 코드!!

app.use(express.json());
app.use(express.urlencoded({ extended: true }))
  1. Client에서 Request를 줘야 하는데 현재 만들어둔 Client가 없기에 POSTMAN이라는 API를 통해 request를 보낼 수 있다. 추후 Client는 React로 만들 예정.
  2. Register Route 만들기 http://localhost:5000/register
    • Post method를 이용하여 register route를 만들고, User.js에 있는 데이터들을 가져오기위해 import 한다.
// index.js
	
const { User } = require("./models/User");
	
app.post("/api/users/register", (req, res) => {
//회원 가입 시 필요한 정보들을 Client에서 가져오면 그 값들을 데이터 베이스에 넣어줌
const user = new User(req.body); //유저가 입력한 로그인 정보들을 DB에 넣기위함.
user.save((err, userInfo) => {
//save는 mongoDB method임
  if (err) return res.json({ success: false, err });
  //error발생한 경우 클라이언트에 json형식으로 전달
  	return res.status(200).json({ success: true });
    //status(200)은 성공한 상태를 뜻함.
  	//성공했을때도 json 형식으로 클라이언트에 메세지 전달.    	
  });
});
  1. POSTMAN APP 통해서 register route에서 회원가입 해보기
    • POST 모드로하고 url 입력: http://localhost.5000/register 데이터 입력은 JSON형식으로 설정한다.
    • 회원가입 시 필요한 데이터들 작성 (userSchema에 각각의 항목들에 required(필수입력)옵션을 넣지 않았기 때문에 항목들 전부 작성할 필요 없음)
    • 회원가입에 성공했다면 { "success": true }가 뜬다.



🔸 NODE MON 다운로드

  • 노드 서버에서 코드 혹은 소스가 업데이트된 경우 서버를 종료 후 재시작해야 적용이 되었지만, Node Mon이라는 Tool을 이용하면 개발자가 소스를 변경 시 감지하여 자동으로 서버를 재시작 해준다.
    • 설치: npm install nodemon --save-dev (-dev: 개발자모드로 다운로드)
  • package.json 파일 > script 추가
  "scripts": {
    "start": "node index.js",
    "dev": "nodemon index.js", // node-mon으로 서버 시작하기위한 코드
  },
  • 서버 실행: npm run dev하여 실행 후 코드 수정하고 리프레시하면 서버를 종료 후 재시작하지 않아도 적용되는 모습을 확인할 수 있다.

🔸 소스 안에 있는 비밀 정보를 보호하기

  • 비밀정보: 개발자의 mongoDB 아이디 및 비밀번호가 들어간 connect code.
  • 보안화를 위해 환경변수 process.env.NODE_ENV를 Local 개발환경일 때의 설정과, 예를 들어 heroku같은 서비스를 통해 배포(deploy)할 때의 설정을 각각 해준다.
    a. config 폴더 > dev.js (개발환경에서 설정할 것)
    b. config 폴더 > prod.js (배포환경에서 설정할 것)
    c. config 폴더 > key.js (환경변수가 개발환경인지 배포환경인지에 따라 실행시킬 if문 삽입)
  • 마지막으로는 보안이 필요한 파일(dev.js)을 .gitignore에 리스트를 업로드 해주어 git 업로드를 막는다.
  • index.js에 config의 key 파일을 불러와서 connect code 부분을 대체한다.
const config = require("./config/key");

const mongoose = require("mongoose");
mongoose
  .connect(config.mongoURI)
  .then(() => console.log("MongoDB Connected..."))
  .catch((err) => console.log(err));

🔸 Bcrypt 라이브러리를 이용하여 유저의 password를 암호화하기

  • 사용자가 회원가입 시 입력한 로그인 정보는 id, email와 password까지 그대로 데이터베이스에 공개적으로 저장이 되어있기에 보안성이 부족하다. 따라서 Bcrypt를 이용하여 유저의 password를 암호화하여 DB에 저장할 것이다.
    - 설치: npm install bcrypt --save
  1. 유저가 register route에서 User info를 save하기 전에 실행할 함수를 User.js에 추가해준다. 따라서 mongoose method인 pre()를 사용한다.
  2. User.js에 bcrypt와 saltRounds를 import 해온다.
  3. 먼저 Salt를 생성(genSalt)해야하는데 이는 유저의 비밀번호를 암호화할 소스코드이며, saltRounds는 salt를 몇자리로 만들 것인지 정하는 코드이다. (예시: saltRounds = 10 이면 10자리의 소스로 유저의 비밀번호를 암호화한다는 의미이다.), hash는 salt를 통해 암호화된 유저의 비밀번호 코드이다.
// User.js

const bcrypt = require("bcrypt");
const saltRounds = 10; // 10자리 소스로 salt생성

// mongoose method pre('save', 동작할함수입력): save하기 전 동작할 함수 입력
// parameter 'next': index.js의 save가 실행되도록 넘겨줌
userSchema.pre("save", function (next) {
  var user = this; // userSchema의 Object들을 가리킴
  // user가 password 값을 변경할때만 실행(비밀번호 외의 정보들을 변경할 때는 아래 작업을 실행하지 않음)
  if (user.isModified("password")) {
    // 유저 비밀번호 암호화: genSalt(salt 생성하는 코드)
    bcrypt.genSalt(saltRounds, function (err, salt) {
      if (err) return next(err); // err발생 시 user.save로 넘어감
      bcrypt.hash(user.password, salt, function (err, hash) {
        if (err) return next(err);
        user.password = hash; // 성공 시, 유저의 plain password를 hash(암호화된 코드)로 표출
        // hash의 첫번째 인자: myPlaintextPassword (user가 입력한 실질적인 password)
        // 따라서 여기선, user.password를 hash의 첫번째 인자로 넣는다.
        next(); // 완료 후 next로 넘겨 user.save되도록 함
      });
    });
  } else {
    next();
  }
});
  1. POSTMAN에서 test용 로그인정보를 생성 후 mongoDB에서 확인해본다. (mongoDB - View Monitoring - Collections 탭에 들어가보면 추가된 유저의 비밀번호가 암호화된 소스로 출력되는 것을 확인할 수 있다.)


🔸 로그인 Route 만들기

  1. Client에서 요청한 email을 DB에 저장되어있는 email인지 찾아야한다. mongoDB method인 findOne()을 이용하여 User model에서 찾는다. : User.findOne()
  2. 요청한 email이 DB에 있다면 Client가 요청한 password와 DB의 password가 같은지 확인해야한다. 그런데 Client에서 요청한 plainPassword를 다시 Bcrypt를 이용하여 암호화한 후에 DB에 있는 해당 유저의 hashed password(암호화된 패스워드)와 같은지 확인해야한다. 따라서, comparePassword라는 method를 User Model에서 만들고(userSchema.methods.comparePassword) 해당 method를 index.js에도 가져와 사용한다. (user.comparePassword)
  3. 만약 클라이언트에서 요청한 password와 DB의 password가 같다면 해당 userInfo에 Token을 생성해준다. 토큰 생성을 위한 JSONWEBTOKEN 라이브러리 설치
    • 설치: npm install jsonwebtoken --save
  4. Token생성을 위한 method를 User.js에 생성해준다. (userSchema.methods.generateToken)
  5. 생성한 token은 쿠키, 로컬스토리지, 세션스토리지 등에 저장 가능한데 여기선 Cookie에 저장하기로 하고, 이를 위한 라이브러리 설치한다.
    • 설치: npm install cookie-parser --save
  6. index.js의 generateToken에서 생성된 token을 cookie에 담아준다.
  7. 정상적으로 작동하는지 테스트하기 위해, POSTMAN에서 POST모드로 http://localhost/5000/login 에 접속하여 이미 회원가입되어있는 유저의 이메일과 비밀번호를 입력하고 Send한다. Success된 것을 확인 후 생성된 토큰을 mongoDB에서 확인할 수 있다.
  8. 즉 로그인 성공 시, 생성된 Token은 Client에선 Cookie에 저장되고, Server쪽에서는 Database의 해당 User model에 저장된다.
  • 로그인 성공한 유저는 DB에서 생성된 token을 확인할 수 있다.
// index.js

const cookieParser = require("cookie-parser");
app.use(cookieParser());
 
// Login Route
app.post("/api/users/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: "비밀번호가 틀렸습니다.",
        });
      // 비밀번호까지 맞다면 Token을 생성하기.
      user.generateToken((err, user) => {
        if (err) return res.status(400).send(err); //status(400): 에러가 있는 경우
        // 토큰을 쿠키에 저장하기위한 라이브러리 cookieParser
        res
          .cookie("x_auth", user.token) //cookie에 token을 "x_auth"라는 이름으로 넣음
          .status(200) //status(200): 성공한 경우
          .json({ loginSuccess: true, userId: user._id });
      });
    });
  });
});
 
// User.js

userSchema.methods.comparePassword = function (plainPassword, cb) {
  // plainPassword를 암호화한 hashedPassword와 같은지 체크
  bcrypt.compare(plainPassword, this.password, function (err, isMatch) {
    // plainPassword를 다시 암호화해서 DB에 있는 hashedPassword와 같은지를 체크해야하기에 bcrypt 사용
    if (err) return cb(err); // false일때.
    cb(null, isMatch); //true일때 즉, callback할 내용: null(err없으니 보낼 err메세지 없음), isMatch는 true
  });
};

const jwt = require("jsonwebtoken");
userSchema.methods.generateToken = function (cb) {
  // jsonwebtoken 이용하여 token생성하기
  var user = this;
  var token = jwt.sign(user._id.toHexString(), "secretToken");
	//user._id: DB에 있는 유저들의 _id값임, toHexString(): String형태로 변환하기 위함.
	//user._id + 'secretToken' = token
  user.token = token; //위와 같이 생성한 토큰을 user model의 token으로 넣어주는 코드
  user.save(function (err, user) {
    if (err) return cb(err);
    cb(null, user);
  });
};

🔸 Auth (Authentication) Route 만들기

  • 사용자의 권한마다 이용할 수 있는 페이지가 나누어져 있다. (로그인을 해야 접속이 가능한 페이지, 로그인 없이도 조회가 가능한 페이지 등) 이러한 페이지마다의 접근 권한을 인증(authentication) 기능을 통해 해당 유저가 어떤 권한을 가진 유저인지 체크한다.
  • 한 유저가 특정 페이지로의 접근을 요청할 경우, Client의 Cookie에 저장된 Token을 Server로 전달한다. 그러면 Server는 Incode되어있는 상태인 Token을 Decode(복호화)하면 DB에 있는 '_id'값이 나온다. 왜냐하면 우리가 위에서 만든 Token의 구조는 token = user._id + 'secretToken' 이기때문이다. 따라서 이 user._id 값으로 DB에 해당하는 유저의 token을 찾아서 해당 유저의 쿠키 토큰과 DB의 토큰이 일치한다면 Authentication이 True가 되고 클라이언트의 특정 페이지 접근 요청에 대한 response를 한다. 만약 불일치하여 Auth가 false가 되면 그에 따른 접근 권한을 주지 않는 등의 response를 한다.
  1. 먼저 index.js에 Auth Route를 만든다. app.get("/api/users/auth", auth, (req, res) => {});
    (2번째 인자인 auth는 middleware로 callback함수가 실행되기 전에 실행되는 것이다. /middleware/auth.js)
  2. User.js에서는 findByToken이라는 statics를 생성한다. 클라이언트의 토큰을 jsonwebtoken 라이브러리를 이용하여 decode하고 user.findOne method를 통해 DB에 보관된 토큰을 찾아서 일치하는지 확인한다.
  3. auth.js 에서는 User.js에서 만든 findByToken을 가져와서 인증에 필요한 코드들을 작성한다.

🔸 Log-out 기능 만들기

  • 로그아웃하려는 유저를 DB에서 찾아서 그 유저의 토큰을 삭제하면 인증 기능(클라이언트의 쿠키에 저장된 토큰과 DB의 토큰과 대조해서 토큰이 틀리면 인증이 거부됨)이 풀리면서 로그인 권한이 사라지고 페이지를 이동시킨다.
  • 로그아웃 Route 생성하기. findOneAndUpdate method 사용
// index.js

app.get("/api/users/logout", auth, (req, res) => {
  User.findOneAndUpdate({ _id: req.user._id }, { token: "" }, (err, user) => {
    if (err) return res.json({ success: false, err });
    return res.status(200).send({
      success: true,
    });
  });
});
  • POSTMAN에서 /api/users/logout에 접속하고 GET으로 놓고 유저의 이메일과 암호를 SEND한다. 그러면, 아래와 같은 결과가 뜬다.

  • 그리고 DB에 가서 확인 해 보면, 로그아웃 시 token이 지워진 것을 확인할 수 있다.


🔷 FRONT-END ( Client )

🔹 React.js

  • React의 Props: Properties의 줄임말로 Component 간에 어떤 요소들을 소통할 때 쓰는 문법이다. 부모 컴포넌트에서 자식 컴포넌트에게 보낼 수 있다. 자식 컴포넌트에게 보내진 Props의 값은 변경될 수 없다. 부모 컴포넌트에서 자식 컴포넌트에게 변경된 props를 다시 보내지 않는 이상 자식 컴포넌트에서의 Props는 자체적으로 변경할 수 없다.
  • React의 State: 한 컴포넌트 안에서 데이터를 전달할 때 쓰인다. State의 값은 변할 수 있고, State이 변하면 re-render된다.
  • Babel: 최신 자바스크립트 문법을 지원하지 않는 브라우저들을 위해서 최신 자바스크립트 문법을 구형 브라우저에서도 적용할 수 있도록 변환 시켜주는 도구.
  • Webpack: 많은 모듈들을 묶어주는(bundle) 도구. create-react-app 프로젝트 폴더에서 src폴더 내부의 파일들만 Webpack이 관리해준다. 따라서 개발하는데 있어서 쓰일 이미지파일이나 각종 변동되는 파일들은 src폴더에 생성하고 수정하는게 보편적이다.
  • 기존의 React는 위와같이 Babel, Webpack 등을 직접 설정 해줘야하는 부분들이 있었지만, create-react-app을 이용하면 이러한 도구들이 편리하게 디폴트로 설정되어진다.
    - 설치: npx create-react-app 생성할 프로젝트명
    - Cf. npx create-react-app . "."을 붙여주면 해당 폴더의 경로에 react 라이브러리를 설치하겠다는 명령어이다.
  • React에서는 Page(Component)이동 시 React Router Dom을 사용한다.
    - 설치: npm install react-router-dom --save
  • Boiler-plate는 Front 관련 작업은 'client' 폴더에서 React 설치하여 진행하며, Back 관련 작업은 'server'폴더에서 진행한다.
  • Front-end 관련: client > src 폴더 내부 구조 설명
    a. _action, _reducer : Redux를 위한 폴더들
    b. component/views : Page들
    c. components/views/Sections : Page에 관련된 css파일이나 component들
    d. App.js : Routing 관련 처리
    e. Config.js : 환경 변수관련 처리
    f. hoc : Higher Order Component의 약자로, 한 컴포넌트 안에서 다른 컴포넌트를 포함하여 갖는 Function이다. 예시) 유저가 로그인을 했을 때 해당 유저의 role(권한)에 따라 특정 페이지를 연결해줄 것인지 아닌지를 판단하여 처리해주는 기능.
    g. utils : 여러 페이지에서 쓰일 수 있는 것들을 넣어둠
  • POSTMAN api를 통해 대체했었던 Client 부분을 React로 적용할 것임.
  • React에서 서버에 request할때 AXIOS를 사용할 것임.
    - AXIOS 설치: npm install axios --save

🔹 CORS 이슈, Proxy 설정

  • 클라이언트에서 axios로 request를 보냈을때 에러가 발생한다. 서버와 클라이언트의 포트번호는 아래와 같이 다르고, 이렇게 다른 포트를 가지고 있는 서버는 각각의 설정을 해줘야만 Request를 보낼 수 있다. 이는 Cors 정책 때문인데, CORS(Cross-Origin Resource Sharing)는 서로 다른 Origin끼리는 보안상 문제로 CORS에 의해 통제받는다는 것이다. 이를 해결할 수 있는 방법 중 하나로 Proxy를 이용하는 것이다.
    - Back-end server port: http://localhost:5000/
    - Front-end server port http://localhost:3000/
  • Client 폴더 경로에서 Proxy 설치: npm install http-proxy-middleware --save
  • Proxy 설치 후 src/setupProxy.js 생성하여 proxy의 origin target을 5000포트로 설정해준다.

🔸🔹 Concurrently 라이브러리 설치

  • 클라이언트 서버를 각각 npm run start 해줘야 했던 불편함을 해결해주는 라이브러리.
    - server 경로에 설치: npm install concurrently --save
  • server / package.json > script에 실행할 커맨드들을 입력해준다.
  • 아래와 같이 npm run dev를 입력하면 백서버와 리액트 서버를 둘다 실행시켜준다.
// server 폴더의 package.json

  "scripts": {
    "start": "node server/index.js",
    "backend": "nodemon server/index.js",
    "test": "echo \"Error: no test specified\" && exit 1",
    "dev": "concurrently \"npm run backend\" \"npm run start --prefix client\""
	//"npm un start --prefix client"는 client폴더의 React 서버 실행 명령어이다.

🔹 CSS Framework for React JS

  • Ant Design을 사용 https://ant.design/
    - 설치: npm install antd --save
  • client > src > index.js에 불러오기: import 'antd/dist/antd.css';

🔹 Redux 상태 관리 라이브러리 사용하기

  • 리덕스는 상태 관리 라이브러리로 React의 Stata를 관리해주는 Tool이라고 보면 된다.
  • Action: 상태에 무슨 일(액션)이 일어났는지 설명하는 오브젝트 형태.
  • Reducer: 상태 변화가 일어날 것을 설명하는 함수 형태. 이전 Stata와 action object를 받은 후에 next state를 return함.
  • Store: State을 감싸주는 역할을 하는 Object로 몇가지 method들을 통해 이용할 수 있다. 또한 만약 store에 있는 state를 변경하고 싶다면 dispatch(action)를 사용하여 변경 가능.
  • Redux의 Store는 기본적으로 object 형태의 action만 dispatching하는데, redux middle ware를 이용하여 plain object 외의 Function이나 Promise 형태의 action도 dispatching하도록 할 수 있다.
  • Client에 설치할 아래 4가지 Dependency. (3, 4번은 redux middle ware)
    1. Redux
    1. React-redux
    2. Redux-promise: Dispatch에 Promise 형태를 받을 수 있도록 도와주는 tool.
    3. Redux-thunk: Dispatch에 Function 형태를 받을 수 있도록 도와주는 tool.
    • 설치: npm install redux react-redux redux-promise redux-thunk --save
  • Redux의 라이브러리 중 combineReducers를 이용하여 state마다 나눠져있을 reducer들을 rootReducer로 하나로 통합시켜주는 작업을 진행할 수 있다. src/_reducers/index.js 참고.

🔹 로그인 페이지 구현

  • 유저의 email, password 등을 useState로 state화 하고, submit한 데이터를, AXIOS를 이용하여 서버로 전송한다. 다만, 해당 프로젝트에서는 Redux도 사용할 것이기때문에 AXIOS를 이용하여 보내는 것이 아닌, redux의 useDispatch 라이브러리를 사용하여 action을 생성한다. 그리고 로그인 성공 시, react-router-dom 라이브러리의 useNavigate를 사용하여 시작페이지(LandingPage)로 보내준다.

🔹 회원가입 페이지 구현

  • 로그인 페이지와 같은 형식으로 구현한다. 유저가 회원가입 시 필요한 항목 4가지: email, name, password, confirmPassword를 State화하고 유저가 입력한 password와 confirmPassword가 같지 않을 시 경고창 알림 기능 삽입, 회원가입 성공 시 useNavigate를 이용하여 LoginPage로 이동한다. 실패할 경우 회원가입에 실패해다는 alert 띄운다.

🔹 로그아웃 기능 구현

  1. LandingPage에 로그아웃 버튼을 만들고 onClick 이벤트를 설정한다.
  2. Axios를 통해 서버 측에 만들어 놓은 logout (DB에 저장된 유저의 아이디를 찾아보고 해당 아이디가 있으면 DB에 저장 되어있는 해당 유저의 Token 값을 삭제하는 동작 실행)을 get method를 이용하여 서버 데이터를 요청한다.
  3. 요청된 데이터의 response가 success라면 useNavigate를 통해 LoginPage로 이동한다, 만약 실패하면 로그아웃 실패 alert 띄운다.

🔹 유저의 인증 및 권한에 따른 Page 접근 예시

  1. 아무나 진입 가능한 페이지: LandingPage, AboutPage
  2. 로그인한 회원만 진입 가능한 페이지: DetailPage
  3. 로그인 한 회원은 진입 못하는 페이지: RegisterPage, LoginPage
  4. 관리자만 진입 가능한 페이지: AdminPage
  • 접근 통제를 위해 HOC(Higher Order Component)라는 function을 사용. HOC는 한 컴포넌트를 받아 새로운 컴포넌트로 return한다.
  • 접속한 유저가 특정 페이지로 이동할 권한이 있는지 확인 후 권한이 있다면 해당 페이지로 이동시켜주고, 권한이 없다면 다른 페이지로 이동시킨다.
  • 따라서 HOC를 사용한 Auth 컴포넌트를 생성하여 페이지들의 인증을 통제할 수 있다.
profile
프론트엔드 개발을 공부하는 예비 개발자입니다😸

0개의 댓글