1. 기존에 src > databases > user.json파일에 저장했던 회원가입 정보들을 삭제하고, db와 연결할 파일 생성하기

  -src > config 폴더 생성 > config 폴더 내에 db.js 파일 생성

// db.js

const mysql = require("mysql");

const db = mysql.createConnection({
  host: "AWS RDS에 만든 데이터베이스의 엔드포인트 복사하여 붙여넣기",
  user: "데이터베이스 생성 시 설정했던 유저 이름",
  password: "데이터베이스 생성 시 설정했던 비밀번호",
  database: "데이터베이스 생성 시 설정했던 데이터베이스 이름"
});

db.connect();

module.exports = db;

 

 

2. UserStorage.js 파일에서 로그인과 회원가입을 json 파일로부터 file system을 통해 받아오던 것을 db와 연결하기

// UserStorage.js

const db = require("../config/db");

class UserStorage{

  static getUserInfo(id) {
    return new Promise((resolve, reject) => {                          // 성공 시 resolve, 실패 시 reject 반환
      const query = "SELECT * FROM users WHERE id = ?;";      // 로그인 시행 시 db로부터 로그인 정보를 불러올 쿼리문 작성
      db.query(query, [id], (err, data) => {                              // 쿼리문에서 ?안에 들어갈 정보를 [id]로 설정
        if (err) reject(`${err}`);                                             // error가 [Object ocject]로만 뜨지 않고 문자열로 뜰 수 있도록 처리
        resolve(data[0]);
        // 로그인에서 id = id인 것이 있다면 성공한 것으로, data를 불러오는데, data가 [{id:~, name:~, psword:~}]형식이므로 첫번째 것만 불러올 수 있도록 data[0]으로 처리
      });
    });
  }
  
  static async save(userInfo) {
    return new Promise((resolve, reject) => {                 // 성공 시 resolve, 실패 시 reject 반환
      const query = "INSERT INTO users(id, name, psword) VALUES(?, ?, ?);";
      // 회원가입은 회원가입 창에서 입력한 id, name, psword를 받아서 users 테이블에 INSERT하는 것으로 처리
      db.query(query, [userInfo.id, userInfo.name, userInfo.psword], (err) => {
        if (err) reject(`${err}`);
        resolve({ success: true });
        // 성공하면 따로 보낼 데이터는 없고 msg만 { success: true }로 전달
      });
    });
  }
  
  moduel.exports = UserStorage;

 

 

3. User.js파일에서 login에 대한 동작을 try, catch문으로 변경

// User.js

class User{

  ...
  
  async login() {
    const client = this.body;
    try {
      const {id, psword } = await UserStorage.getUserInfo(client.id);
      if (id) {
        if (id === client.id && psword === client.psword) {
          return { success: true };
        }
        return { success: false, msg: "비밀번호가 틀렸습니다." };
      }
      return { success: false, msg: "존재하지 않은 아이디입니다." };
    } catch(err) {
      return { success: false, msg: err };
    }
  }
  
  ...
}

 

 

4. 결과

  - 회원가입

  - 정보 입력 후 SIGN UP 클릭 시 데이터베이스에 해당 정보가 저장됨

 

  - 로그인

  - 새로 회원가입했던 id와 비밀번호로 로그인을 시도하면 성공

  - 로그인 성공 시 이동하도록 지정한 루트 페이지로 이동함

1. curl 명령어

 -터미널에서 localhost에 접근하여 get 또는 post 요청을 시험해볼 수 있음

 1) curl http://localhost:3000/login

  -curl 뒤에 입력한 localhost 주소의 html 문서를 호출

 

 

 2) curl http://localhost:3000/login -X POST -d '{"id":"user1","pw":"1234"}' -H "Content-Type: application/json"

  -'-X POST'는 post 요청을 하겠다는 의미

  -'-d'는 데이터를 의미하며 뒤에 json형태의 문자열을 넣어 해당 주소(http://localhost:3000/login)에 넘겨줄 데이터를 지정

  -'-H "Content-Type: application/json"'를 사용하여 헤더를 지정, 넘겨줄 데이터의 형식을 json이라고 명시해줌

  -login 경로에 미리 json파일로 저장해뒀던 아이디, 비밀번호 쌍 중 하나를 입력하여 post 요청을 하고, 그 응답으로 {"success": true}가 출력됨

  -다른 경우(아이디 오류, 비밀번호 오류)에 대해서도 각각의 요청에 대한 응답이 잘 출력됨

 

 3) curl http://localhost:3000/register -d '{"id":"user123","pw":"1234"}' -H "Content-Type: application/json"
  -회원가입 경로에 데이터를 전달하기

  -'-d'옵션을 통해 데이터를 전달해주는 부분이 있으면, 자동으로 post 메서드로 인식하기 때문에 '-X POST'는 없어도 됨

  -회원가입 페이지에 id와 pw 쌍을 입력하고 '-H "Content-Type: application/json"'을 이용해 넘겨줄 데이터가 json 형식임을 명시

  -데이터를 잘 넘겨받아 그에 대한 응답으로 {"success": true}를 출력했으며, 실제 회원가입 데이터를 저장하는 json 파일에도 새로운 데이터가 잘 저장됨

 

 

2. POSTMAN

 -API를 테스트해볼 수 있는 프로그램

 1) 다운로드 / 설치

  -구글에 postman을 입력 후 postman 다운로드

 

  -다운로드 후 설치 하고, 프로그램 실행

  -workspace > My Workspace

 

 2) API 테스트

  -new에서 HTTP Request

 

 

 2-1) GET 테스트

  -GET으로 지정한 곳 뒤에 localhost 주소를 입력한 뒤 send를 클릭하면 다음과 같이 해당 주소의 html문서를 볼 수 있음

 

 2-2) POST 테스트

  -GET을 POST로 바꾸면 POST 요청 실행 가능

  -body 탭에서 형식은 json으로 지정해주고 post할 데이터를 json 형태로 { "id": "user1", "pw": "1234" }와 같이 작성한 뒤 send

  -정상적으로 저장되어 있는 아이디와 비밀번호를 요청으로 보내주었으므로 { "success": true }를 응답으로 받을 수 있음

 

  -회원가입 경로에서도 새로운 로그인과 마찬가지로 id와 pw를 입력한 뒤 send 해주면 정상적으로 json 형식의 데이터를 받아 저장하고, { "success": true }로 응답해줌

 

  -또한, 위에서 입력한 id와 pw는 회원가입 정보를 받아 저장해두는 json파일인 users.json 파일에 추가로 저장되어 있음

 

 3) POSTMAN 폴더 관리

  -collection의 '+'를 눌러 새로운 폴더 생성

 

  -폴더의 이름 지정 가능

 

  -Add a request 버튼을 클릭하여 새로운 request 저장가능

 

  -request의 이름도 지정할 수 있으며, 그 외에는 위에서 한 것과 동일하게 설정하여, 반복적으로 테스트 해보고 싶은 API를 저장해두면 됨

·회원가입 화면에서 id, name, pw, pw확인을 입력한 뒤 SIGN UP 버튼을 누르면 서버에서 입력된 데이터를 파일에 저장하는 로직

 

1. index.js 파일에 "/register" 경로에 post로 요청이 오면 ctrl.process.register 함수가 실행되도록 요청되어 있음

// index.js

router.post('/register', ctrl.process.register);

 

2. home.ctrl.js 파일에서 process내에 register 함수를 보면 user클래스 내의 reigster가 실행되도록 되어 있음

// home.ctrl.js

const process = {
    login: async (req, res) => {
        const user = new User(req.body);
        const response = await user.login();
        return res.json(response);
    },
    
    register: (req, res) => {
        const user = new User(req.body);
        const response = user.register();
        return res.json(response);
    },
};

 

3. User.js 파일의 user 클래스에서 register()함수를 보면 save메서드를 UserStorage 파일에서 save 메서드를 호출하도록 되어 있음

// User.js에서 user클래스 내부

register(){
  const client = this.body;
  const response = UserStorage.save(client); // constructor에서 넘겨준 body를 그대로 저장
  return response;
}

 

4. UserStorage.js에서 save메서드를 "/register"경로에서 입력받은 값을 파일에 저장하는 메서드로 구현

// UserStorage.js


// save 메서드를 실행할 때 users 데이터 전체를 넘겨주기 위해 코드 수정
static getUsers(isAll, ...fields) {
  return fs
    .readFile("./src/databases/users.json") // 해당 경로에서 파일 읽어오기
    .then((data) => {  // 파일 읽어오는 것을 성공하면
      return this.#getUsers(data, isAll, fields);  // 은닉화하여 생성한 함수 #getUsers 실행
    })
    .catch(console.error);  // 파일 읽기에 실패하면 error 반환
}


// getUsers 메서드에서 파일 읽어오는 것에 성공했을 때 시행할 명령 정리
static #getUsers(data, isAll, fields) {
  const users = JSON.parse(data);
  if (isAll) return users; // isAll이 true이면 전체 데이터 바로 반환하기
  
  const userUsers = fields.reduce((newUsers, field) => { // 각각의 id, pw, name 필드 각각 반환
    if (users.hasOwnProperty(field)) {
      newUsers[field] = users[field];
    }
    return newUsers;
  }, {});
  return userUsers;
}


// 데이터를 그냥 추가하면 원래의 데이터가 사라지고 덮어씌워지므로,
// 원래의 데이터를 불러와서 새로운 데이터를 추가하고,
// 새로운 데이터를 추가한 데이터 전체를 파일에 저장해야됨
// users 데이터를 모두 불러오는 메서드(위에 있는 getUsers) 사용하여 getUsers가 반환한 모든 파라미터 다 받아오기

// 데이터를 읽어오는데 시간이 걸리므로 다 읽어올 때 까지 기다리도록 async 함수로 선언하고 getUsers 메서드는 await로 처리
static async save(userInfo) {
  const users = await this.getUsers(true);
  
  if (users.id.includes(userInfo.id)) {
    throw "이미 존재하는 아이디입니다."; // error를 통해 명령하면 object로 반환되므로 문자열 그대로 넘겨주기
  }
  users.id.push(userInfo.id);
  users.name.push(userInfo.name);
  users.pw.push(userInfo.pw);
  fs.writeFile("./src/databases/users.json", JSON.stringify(users));
  return { success: true };
}

 

 

5. 위에서 회원가입을 실행하기 위해 거치는 다른 파일들에도 asynx, awiat를 걸어 파일을 읽어오는 시간동안 기다리도록 명령

// User.js의 user 클래스 내부

async register(){ // async 함수로 변경
  const client = this.body;
  const response = await UserStorage.save(client); // awiat 처리
  return response;
}


// home.ctrl.js

const process = {
    login: async (req, res) => {
        const user = new User(req.body);
        const response = await user.login();
        return res.json(response);
    },
    
    register: async (req, res) => { // async 함수로 변경
        const user = new User(req.body);
        const response = await user.register(); // awiat 처리
        return res.json(response);
    },
};

 

 

6. 또한, User.js 파일에서 register 메서드는 이미 존재하는 아이디에 대한 예외 처리 코드 추가

// User.js의 user 클래스 내부

async register() {
  const client = this.body;
  try {
    const response = await UserStorage.save(client);
    return response;
  } catch (err) { // 에러 발생 시, UserStorage에서 throw해준 메세지, "이미 존재하는 아이디입니다."를 출력
    const a = { success: false, msg: err };
    console.log(a.msg);
    return a;
  }
}

 

 

7. 결과

 -서버 실행 후 "/register" 경로에서 아이디, 이름, 비밀번호, 비밀번호 확인 입력 후 SIGN UP을 누르면, users.json파일에 해당 정보 저장

 

 -원래 users.json

 -회원가입

 -회원가입 후 users.json(회원가입 창에서 새로 입력하고 SIGN UP을 누른 아이디, 이름, 비밀번호가 추가로 저장되어 있음)

1. UserStorage.js에 있던 사용자 id, pw, name 정보를 파일로 따로 만들기

 -src 폴더 안에 DB용 폴더 생성(src > databases > user.json)

 -user.json파일에 is, pw, name을 담고 있던 사용자 객체를 json 형식으로 복사(각 변수의 이름을 문자열로 처리해주기)

  // user.json

        {                
            "id": ["사용자1", "사용자2", "사용자3"],
            "pw": ["1234", "3456", "5678"],
            "name": ["이름1", "이름2", "이름3"]
        }

 

 

2. UserStorage.js 폴더에 있던 사용자 객체는 지우고 대신, 데이터 파일에 접근할 수 있도록 file system 불러오기

// UserStorage.js

const fs = require("fs")

 

 

3. UserStorage.js 폴더에 있던 #users객체를 지웠으므로 로그인을 위한 메서드였던 static getUserInfo()에 있던 users도 fs에서 불러오도록 변경

 -id와 id, pw, name이 저장된 파일을 불러온 뒤 비교하는 이후의 과정은 파일을 불러오는 fs.readFile이 성공했을 때 실행(.then)

 -그 외 에러가 나면 예외 처리(.catch)

// UserStorage.js (버전 1)

static getUserInfo(id) {
  return fs.readFile("./src/databases/users.json")
    .then((data) => {
      const users = JSON.parse(data); // json형태릐 데이터를 읽는 함수
      const idx = users.is.indexOf(id);
      const usersKeys = Object.keys(users);
      const userInfo = usersKeys.reduce((newUser, info) => {
        newUser[info] = users[info][idx];
        return newUser;
      }, {});
      return userInfo;
    })
    
    .catch(console.error);
}
// UserStorage.js (버전 2)(깔끔하게 함수로 정리한 버전)

static getUserInfo(id) {
  return fs.readFile("./src/databases/users.json")
    .then((data) => {
      return this.#getUserInfo(data, id);
    })
    
    .catch(console.error);
}

static #getUserInfo(data, id) { // 파일 불러오기 성공 시 수행되는 동작을 깔끔하게 함수로 묶어 빼주기
  const users = JSON.parse(data);
  const idx = users.is.indexOf(id);
  const usersKeys = Object.keys(users);
  const userInfo = usersKeys.reduce((newUser, info) => {
    newUser[info] = users[info][idx];
    return newUser;
  }, {});
  return userInfo;
}

 

 

4. User.js 파일에서 login()함수를 UserStorage함수가 바뀐 것에 따라 바꿔주기

// User.js

"use strict";

class User{
  // constructor 생략
  
  async login() {
    const client = this.body
    
    // UserStorage에서 getUserInfo를 실행할 때, json파일을 불러올 때 시간이 걸림
    // javascript는 비동기 처리를 하므로 json파일을 다 불러올 때까지 기다리지 않고 이 id, pw 비교 작업을 수행
    // 그에 따라 아직 불러오지 못한 json파일과 비교하며 undefined가 됨
    // 이를 방지하기 위해 await를 써서 UserStorage.getUserInfo가 다 시행될 때까지 기다리는 명령을 부여
    // 이때, await는 async 함수에서만 사용이 가능하므로 login() 함수를 async login()으로 변경
    const {id, pw} = await UserStorage.getUserInfo(client.id);
      if (id) {
        if (id === client.id && pw === client.pw) {
          return {success: true};
        }
        return {success: false, msg: "비밀번호가 틀렸습니다."};
      }
      return {success: false, msg: "존재하지 않는 아이디입니다."};
    }
  
  // register() 생략
}

module.exports = User;

 -await를 사용하지 않고 console.log(fs)를 통해 promise로 설정된 fs를 출력하면 promise: {<pending>}이 출력

  ※ "promise: {}": 데이터를 전부 읽어오지 못했다는 의미

 -또한, User.js파일에서 UserStorage.getUserInfo(client.id)를 console.log로 출력하면 아직 json파일을 불러오지 못해 id가 정의되지 않음

  →undefined가 뜸

 

 

5. controller인 home.ctrl.js파일에서도 login 메서드를 실행할 때 login 메서드가 User.js 파일 내에서 다 실행될 때까지 기다리도록 await 적용

// home.ctrl.js

const process = {
  login: async (req, res) => {
    const user = new User(req.body);
    const response = await user.login();
    return res.json(response);
  },
  
  //register 생략
};

 

1. 아래 사이트를 통한 로그인 페이지 및 회원가입 페이지 구현

 

화면 오픈소스 사이트, codepen

1. https://codepen.io 접속 2. Search Codepen... 에 각종 테마 검색 3. 원하는 테마 선택 후 코드 확인 및 아래의 Comments 확인 4. Comments 클릭 후 가장 아래에 License 확인하기 Copyright (c) 2022 by Aigars Silkalns (https:

data-science-study.tistory.com

 

 -로그인 페이지

<!DOCTYPE html>
<html lang="ko">
    <head>
        <meta charset="UTF-8">
        <title>로그인</title>
        <style>
            ul {list-style:none;}
        </style>
        <script src="/js/home/login.js" defer></script>
        <link rel="stylesheet" href="/css/home/login.css">
    </head>
    <body>
        <div class="login-page">
            <div class="form">
              <form class="login-form">
                <input id="id" type="text" placeholder="아이디"/>
                <input id="pw" type="password" placeholder="비밀번호"/>
                <p id="button">login</p>
                <p class="message">Not registered? <a href="/register">Create an account</a></p>
              </form>
            </div>
          </div>
    </body>
</html>

<!-- Copyright (c) 2022 by Aigars Silkalns (https://codepen.io/colorlib/pen/rxddKy) -->

 

 -회원가입 페이지

<!DOCTYPE html>
<html lang="ko">
    <head>
        <meta charset="UTF-8">
        <title>회원가입</title>
        <style>
            ul {list-style:none;}
        </style>
        <script src="/js/home/register.js" defer></script>
        <link rel="stylesheet" href="/css/home/login.css">
    </head>
    <body>
        <div class="login-page">
            <div class="form">
              <form class="login-form">
                <input id="id" type="text" placeholder="아이디"/>
                <input id="name" type="text" placeholder="이름"/>
                <input id="pw" type="password" placeholder="비밀번호"/>
                <input id="confirm-pw" type="password" placeholder="비밀번호확인"/>
                <p id="button">SIGN UP</p>
                <p class="message">Already registered? <a href="/login">login</a></p>
              </form>
            </div>
          </div>
    </body>
</html>

<!-- Copyright (c) 2022 by Aigars Silkalns (https://codepen.io/colorlib/pen/rxddKy) -->

 

 

2. 회원가입 요청 에 대한 동작을 위해 register.js 파일 생성(login.js 파일과 동일하게 public > js > home 폴더에서 관리)

"use strict";

const id = document.querySelector("#id"),
      name = document.querySelector("#name"),
      pw = document.querySelector("#pw"),
      confirmPw = document.querySelector("#cofirm-pw"),
      registerBtn = document.querySelector("#registerBtn");

registerBtn.addEventListener("click", register);

function register() {
    const req = {
        id: id.value,
        name: name.value,
        pw: pw.value,
        confirmPw: confirmPw.value,
    };

    fetch("/register", {   // register 경로에서
        method: "POST",    // http 메소드 중 POST라는 메소드로 데이터 전달
        headers: {         // 전달하는 데이터가 json 형식이라는 것을 명시
            "Content-Type": "application/json",
        },
        body: JSON.stringify(req) // JSON 객체는 문자열로 감싸져서 출력됨
                                  // 그냥 req는 {id: "id", pw: "pw"}형태, JSON.stringify(req)는 {"id": "id", "pw": "pw"} 형태
    })
        .then((res) => res.json())
        .then((res) => {
            if (res.success) {          // res.success가 true이면
                location.href = "/login"     // "/login" 경로로 이동
            } else{
                alert(res.msg);         // res.success가 false이면 res에 있는 msg를 경고창으로 띄움
            }
        })
        .catch((err) => {   // 회원가입 중 에러 발생 시 console에 에러 표시
            console.error(new Error("회원가입 중 에러 발생")); // 
        });
}

 -기본적으로 login.js의 코드를 복사하여 사용

 

3. User.js와 UserStorage.js파일에도 회원가입 관련 기능 구현

// UserStorage.js

// class UserStorage{}안에 static save 변수 추가
static save(userInfo) {             // User.js에서 client(=this.body)를 인자로 받아옴
  const users = this.#users;        // UserStorage 클래스 내의 #users 객체를 받아와
  users.id.push(userInfo.id);       // 객체 안의 각 리스트에 id, name, pw을 push하여 저장
  users.name.push(userInfo.name);
  users.pw.push(userInfo.pw);
  return { success: true };         // 전부 제대로 저장이 되었다면 success: true 반환
}
// User.js

// class User{} 안에 register() 추가
register() {
  const client = this.body;
  const response = UserStorage.save(client); //constructor에서 넘겨준 body를 그대로 저장하고 UserStorage의 save함수로 넘겨줘 입력한 정보를 저장
  return response; // UserStorage의 save 함수를 실행하여 반환된 success: true값을 똑같이 반환해줌
                   // 반환한 값에 따라 success: true이면 register.js에서 '/login'경로로 이동하라는 명령을 실행
}

 

 

4. Controller인 home.ctrl.js파일에도 User.js파일에서 register함수 처리에 대한 컨트롤을 위해 process에 register 추가

// home.ctrl.js

// 원래 login()만 있던 process 객체에 register 추가
const process = {
    login: (req, res) => {
        const user = new User(req.body);
        const response = user.login();
        return res.json(response);
    },
    register: (req, res) => {
        const user = new User(req.body);
        const response = user.register();
        return res.json(response);
    },
};

 

 

5. index.js에도 /register경로에서의 데이터를 post로 받기 위해 코드 추가

router.get('/register', ctrl.output.register);    // '/register'경로로 들어가면 출력되는 화면 연결
router.post('/register', ctrl.process.register);  // 'register'경로에서 입력되는 데이터 post로 받기

·UserStorage 파일을 만들어 사용자 정보를 따로 관리

1) src 폴더 아래에 models 폴더 생성 > models 폴더 안에 UserStorage.js 파일 생성

// UserStorage.js

"use strict";

class UserStorage{

  // 사용자 정보를 객체로 보관
  // static(정적 변수)로 선언하여 controller에서 클래스를 인스턴스화하지 않고 바로 users변수에 접근가능하도록 함
  // #users처럼 변수 앞에 #을 붙여 public 변수에서 private 변수로 선언하여 외부 파일에서 함부로 불러올 수 없도록 함
  static #users = {
    id: ["사용자1", "사용자2", "사용자3"],
    pw: ["1234", "3456", "5678"],
    name: ["이름1", "이름2", "이름3"]
  };


  // users 변수를 private로 선언하여 불러올 수 없게 한 것을 로그인 확인을 위하여 불러와야 할 때 불러올 수 있도록 함
  static getUsers(...fields) {
    const users = this.#users;                                                 // 위의 users 객체를 this를 통해 복사
    const newUsers = fields.reduce((newUsers, field) => {       // users 객체의 각 변수에 대해
      if (users.hasOwnProperty(field)) {                                   // users 객체에 존재하는 변수에 대해
        newUsers[field] = users[field];                                     // newUsers 객체에 똑같은 변수를 복사
      }
      return newUsers;
    }, {})										  // users를 복사한 newUsers를 객체 형태로 반환
    return newUsers;
  }
  
  
  // 로그인 페이지에서 입력받은 id에 따라 알맞은 pw와 name 반환하기
  ststic getUserInfo(id) {							    // id를 인자로 넘겨 받아(로그인 페이지에서 입력한 id)
    const users = this.#users;
    const idx = users.id.indexOf(id);					    // 인자로 넘겨받은 id의 users 객체 중 id 변수에서의 인덱스를 받아오기 
    const usersKeys = Object.keys(users);                                // users 객체의 key(변수 이름) 가져오기
    const userInfo = userKeys.reduce((newUser, info) => {        // 각 변수의 이름에 대해
      newUser[info] = users[info][idx];                                     // 각 변수의 이름별 인덱스(id의 인덱스, pw의 인덱스 등)을 받음
      return newUsers;
    }, {});                                   // 로그인 페이지에서 입력받은 id를  users 객체의 id 변수에서 찾아 같은 인덱스의 pw, 같은 인덱스의 name을 찾아 객체 형태로 반환
    return userInfo;
  }
}

module.exports = UserStorage; // 외부 파일에서도 UserStorage 클래스를 사용할 수 있도록 exports

 

 

2) UserStorage.js 파일을 만든 models 폴더에 User.js 파일을 생성하여 로그인 모델 구현

// User.js

"use strict";

const UserStorage = require("UserStorage");    // 사용자의 정보를 담고 사용자의 id와 pw를 비교해줄 UserStorage 가져오기

class User {
  constructor(body) {       // 생성자 생성(body의 초기값 설정)
    this.body = body;
  }
  
  login() {                     // 로그인 모델 구현
    const body = this.body                                                                  // this.body가 반복적으로 나오므로 짧게 body로 사용하기 위해 선언
    const { id, pw } = UserStorage.getUserInfo(body.id);                       // UserStorage.js 파일에서 getUserInfo 함수에 인자로 id를 주고 그 id에 해당하는 id와 pw를 객체 형태로 받기
    if (id) {                                                                                         // 그 id가 사용자 정보에 존재한다면
      if (id === body.id && pw === body.pw) {                                    // 그리고 그 id가 로그인 페이지에서 받은 id와 일치하고 pw가 로그인 페이지에서 받은 pw와 일치한다면
        return {success: true};                                                             // {success: true}를 객체로 return
      }
      return {success: false, msg: "비밀번호가 틀렸습니다."};                  // 만약 id는 존재하지만 pw가 틀렸다면 success는 false로, 메세지와 함께 반환 
    }
    return {success: false, msg: "존재하지 않는 아이디입니다."};             // 만약 id가 존재조차하지 않는다면 success는 false로, 메세지와 함께 반환
  }
}

module.exports = User;

 

 

3) Controller(home.ctrl.js)파일에서 로그인 프로세스를 새로 만든 User 클래스를 사용해 바꿔주기

// home.ctrl.js

// 기존 const process에서 아래의 코드로 변경
const process = {
  login: (req, res) => {
    const user = new User(req.body);     // 로그인 페이지에서 로그인 요청과 함께 받은 body(id와 pw)를 User 클래스에 초기값으로 전달
    const response = user.login();          // User클래스의 login 함수 실행하여 id와 pw 일치여부 확인 및 반응
    consoel.log(response);                    // id와 pw에 따른 반응결과를 console에 출력(success 여부 및 메세지)
    return res.json(response);              // json 형태로 반환(페이지에 경고창으로 띄우기 등)
  },
};

 

 

4) 결과

 -입력한 id가 사용자 정보에 없을 때

 

 -입력한 id는 사용자 정보에 있지만 pw가 일치하지 않을 때

 

 -id와 pw가 일치할 때(login.js 파일에서 로그인 성공 시(res.success가 ture일 시) "/"경로로 이동하도록 지정해 놓았으므로 로그인 성공 시 "/" 경로로 이동

 

[Node.js] fetch를 이용해 프런트의 정보를 서버로 보내기

·로그인 페이지에서 입력한 아이디와 비밀번호 받아오기 1) login.js파일에서 로그인 버튼을 눌렀을 때 동작하는 함수에 fetch 기능 추가하기 // login.js function login() { const req = { id: id.value, pw: pw.value,

data-science-study.tistory.com

·이전 글에서 home.ctrl.js 파일에서 login 프로세스가 있을 때 단순히 console.log에 띄우는 작업만 하던 것을 id와 pw를 비교하는 과정으로 변경

 

1) 임의의 id와 pw리스트 지정하고 프런트에서 받은 id, pw와 비교

// home.ctrl.js

// 원래는 controller에 id와 pw 리스트가 있으면 절대 안되지만 연습용으로 controller에 작성
const users = { // 각 사용자의 id와 pw를 리스트로 만들어서 같은 번지에 부여
    id: ["사용자1", "사용자2", "사용자3"],
    pw: ["1234", "3456", "5678"]
};

// login process 작성
const process = {
  login: (req, res) => {
    const id = req.body.id,                         // login.js에서 fetch 안에서 body로 받은 id와 pw를 각각 id와 pw 변수로 받기
           pw = req. body.pw
    if (users.id.includes(id)) {                     // 만약 위에서 임의로 작성한 id 리스트에 프런트에서 받은 id가 존재한다면
      const idx = users.id.indexOf(id);         // 그 id의 인덱스를 idx 변수로 받기
      if (users.pw[idx] === pw){               // 그리고 pw 리스트의 같은 인덱스에 있는 pw와 프런트에서 받은 pw 비교하여 같으면
        return res.json({                            // json 형태로 success: true 전달
          success: true,
        });
      }
    }
    return res.json({                               // 만약 위에서 실패하여 success: true를 return하지 못했다면
      success: false,                                // success: false와 msg: "로그인에 실패하셨습니다."를 json 형식으로 return
      msg: "로그인에 실패하셨습니다.",
    });
  },
};

 

2) login.js에서 success가 true인지 false인지에 따라 응답할 행동 지정

// login.js

function login() {
    const req = {
        id: id.value,
        pw: pw.value,
    };

    fetch("/login", {
        method: "POST",
        headers: {
            "Content-Type": "application/json",
        },
        body: JSON.stringify(req)
    })
    
//////////////////// 여기까지는 동일 ///////////////////////
 
        .then((res) => res.json())
        .then((res) => {
            if (res.success) {                  // res.success가 true이면
                location.href = "/"            // "/" 경로로 이동
            } else{
                alert(res.msg);                // res.success가 false이면 res에 있는 msg를 경고창으로 띄움
            }
        })
        .catch((err) => {                    // 로그인 중 에러 발생 시 console에 에러 표시
            console.error(new Error("로그인 중 에러 발생"));
        });
}

 

3) 확인

  -로그인 실패 시

 -로그인 실패 경고창

 

 

 -로그인 성공 시

 -코드에서 지정한대로 루트 경로로 이동

·로그인 페이지에서 입력한 아이디와 비밀번호 받아오기

1) login.js파일에서 로그인 버튼을 눌렀을 때 동작하는 함수에 fetch 기능 추가하기

// login.js

function login() {
  const req = {
    id: id.value,
    pw: pw.value,
  };
  
  // login 경로에서 / http 메소드 중 POST 메소드를 사용하여 / 전달하는 데이터가 json형식임을 명시
  fetch("/login", {
    method: "POST"
    headers: {
      "Content-Type": "application/json",
    },
    body: JSON.stringify(req) // JSON 객체는 문자열로 감싸져서 출력됨
                                         // 그냥 req는 {id: "id", pw: "pw"} 형식
                                         // JSON.stringify(req)는 {"id": "id", "pw":"pw"}
  });
}

 

2) home.ctrl.js파일 원래는 경로에 따라 화면만 렌더링해주는 명령어만 있었지만 login에 대한 동작도 추가

// home.ctrl.js

"use strict";

// 화면 렌더링(지정된 경로의 주소로 접속했을 때 보이는 화면)
const output = {
    hello: (req, res) => {
        res.render('home/index');
    },
    login: (req,res) => {
        res.render('home/login');
    }
}

// 로그인 프로세스
const process = {
    login: (req, res) => {
        console.log(req.body) // 일단은 제대로 받아와지는지 확인을 위해 login.js 파일에서 body로 준 부분(id와 pw 값) console에 출력
    }
}

// 위의 모듈들을 index.js 파일에서 사용할 수 있도록 오브젝트로 빼주기
module.exports = {
    output,
    process,
}

 

3) index.js파일에서도 login 프로세스를 post를 사용할 수 있도록 코드 추가 및 home.ctrl.js에서 output으로 묶은 hello, login 모듈 에 대한 코드 변경

// index.js

"use strict"

const express = require('express');
const router = express.Router();

// home.ctrl.js에서 넘겨준 오브젝트 받기
const ctrl = require("./home.ctrl");

///////////////// 여기까지는 그대로 ////////////////////////////////

router.get('/', ctrl.output.hello); // output.hello로 변경하여 output안의 hello 모듈 사용할 수 있도록 변경
router.get('/login', ctrl.output.login); // output.login으로 변경하여 output안의 login 모듈 사용할 수 있도록 변경
router.post('/login', ctrl.process.login); // get이 아닌 post로 동작

module.exports = router; // 외부 파일(메인 파일인 app.js)에서 사용할 수 있도록 내보내기

 

4) app.js 파일에서 fetchdml body를 사용할 수 있도록 bodyParser를 등록

// app.js

const bodyParser = require("body-parser"); // home.ctrl.js 파일에서 login.js의 fetch함수에서 body로 넘겨준 것을 잘 받기 위한 모듈 설치

app.use(bodyParser.json()); // bodyParser 미들웨어 등록
app.use(bodyParser.urlencoded({extended: true})); // url을 통해 전달되는 한글, 공백 등의 문자가 포함될 경우 제대로 인식되지 않는 문제 해결

 -터미널에서 "npm install body-parser -s" 명령어로 body-parser 모듈 설치

 

5) 서버 가동 후 동작 확인

  -id와 pw를 입력하고 로그인 버튼을 누르면 터미널에 다음과 같이 id와 pw 값이 출력됨을 알 수 있음

  -id와 pw값 서버로 받기 성공

 

+ Recent posts