[Node.js 찍먹하기] Chapter 05 : 백엔드, 로그인 인증 기능 만들기

프론트 엔드에 입력한 데이터를 이용해 인증을 받자

인증과 인가를 받을려면 어떻게 해야할까

🔙 백엔드에서

기존에 인증 받은 데이터들 === 프론트 엔드에서 입력한 데이터


**const user = { // 프론트엔드에서 입력한 정보로, 해당 사용자의 인증, 인가를 해야함 그리기 위해선 인증 받은 데이터들이 있어야한다(이 데이터랑 프론트 엔드 데이터랑 비교해야함)
    id: ["양상우", "김개발", "박부장"],
    password: ["1234", "1234", "123456"]
}**
  • 이렇게 일단 기존 데이터를 명시를 해주고(사실 이렇게 같은 코드에 있으면 절대 안된다)
  • POST로 들어온 프론트 엔드에서 입력한 데이터를 비교하는 API를 만들자
"use strict"

const output = {
    home: (req, res) => {
        res.render("./home/index") // views는 지정했기땨문
    },

    login: (req, res) => {
        res.render("./home/login")
    }
}

const user = { // 프론트엔드에서 입력한 정보로, 해당 사용자의 인증, 인가를 해야함 그리기 위해선 인증 받은 데이터들이 있어야한다(이 데이터랑 프론트 엔드 데이터랑 비교해야함)
    id: ["양상우", "김개발", "박부장"],
    password: ["1234", "1234", "123456"]
}

const procces = {
    login: (req, res) => {
        const id = req.body.id,
            password = req.body.password;

        if (user.id.includes(id)) { // 데이터에 있으면
            const idx = users.id.indexOf(id); // 해당 id의 인덱스를 가져와서
            if (users.password[idx] === password) { // 해당 위치의 패스워드랑 같으면
                return res.json({
                    success: true // 성공했다고 알려줌
                });
            }
        }
        return res.json({
            success: false, // 성공했다고 알려줌
            msg: "로그인에 실패하였습니다" // 잘 출력되는지 확인해보자
        });
    },
}

module.exports = {
    output,
    procces
};
  • 이렇게 API를 만들었고, 응답을 해줬으니 프론트 엔드는 이 응답을 어떻게 받아야할까?

➬ 프론트에서

.then을 이용한 데이터 처리

fetch로 불러온 데이터는 프로미스 형태로 결과값이 반환된다

"use strict";

const id = document.querySelector("#id"),
    password = document.querySelector("#password"),
    loginBtn = document.querySelector("button");

console.log(id)

loginBtn.addEventListener("click", login)

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

    fetch("/login", {
        method: "POST", // REST API에 맞춰 보냄
        headers: {
            "Content-Type": "application/json" // json으로 보낸다고 말해줌
        },
        body: JSON.stringify(req) // JSON 형태로 바꿔서 body에 실어 보내자
    })
        **.then((res) => res.json()) // 응답 데이터를 가져온다
        .then((res) => console.log(res)) // then을 이용해서 데이터를 가져온다 비동기 처리로 진행되기 떄문에 then을 이용해 동기 처리로 만든다
    // 정리 하자면 fetch에서 login으로 POST를 보내면 해당 API에서 처리를 해왔다, 근데 처리중 응답이 생겼고, 해당 응답을 받아서 사용할려면 백엔드 API의 데이터 처리가 끝나고 나서야 사용할수 있으니, then 을 이용해 데이터가 다 처리된 이후에 res 를 이용한다
    //추가적으로 파라미터로 넘기는 함수에 그 파라미터를 인자로 사용하는 함수 형태이면 축약이 가능하다 .then(console.log)
}**
  • 지금 fetch를 통해 요청(body를 통해서 테이터도 보냄)을 보내고, 해당하는 응답을 프로미스 형태로 받아올것이다
  • API의 데이터를 가져온뒤에 응답을 데이터를 사용해야 하기 때문에 .then을 사용
  • 응답을 데이터를 가져오고 난뒤에 ⇒ 사용해보자

콘솔 말고 어떻게 처리해야할지 정해보자

"use strict";

const id = document.querySelector("#id"),
    password = document.querySelector("#password"),
    loginBtn = document.querySelector("button");

console.log(id)

loginBtn.addEventListener("click", login)

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

    fetch("/login", {
        method: "POST",
        headers: {
            "Content-Type": "application/json" //
        },
        body: JSON.stringify(req)
    })
        .then((res) => res.json())
        .then((res) => {
            if (res.success) { // 응답에서 맞다고 해주면
                location.href = "/"; // 성공하면 페이지 이동
            } else {
                alert(res.msg) // 실패하면 메세지
            }
        })
        .catch((err) => { // 에러 처리
            console.error(new Error("로그인중 에러 발생"))
        })
}
  • 성공하면 홈으로 이동하게 루트 설정해주고
  • 실패하면 실패한 메세지
  • 에러가 생기면 .catch를 이용해 에러 코드를 발생해주자

🔙 다시, 백엔드

MVC의 모델(M) 만들기

모델?

  • 데이터를 가지는 코드
  • 컨트롤 하는 코드
  • 데이터 로직을 처리하는 코드

등등

여튼 저번 ctrl 파일에 있는 데이터 코드를 분리하자

UserStorage.js

"use strict";

class UserStorage {
    static #users = { // class 안에 변수를 선언할때는 const 이런거 안해도 된다 // 은닉화 private 함, 그렇다면 , 접근 말고 사용해야할때는??
        id: ["양상우", "김개발", "박부장"],
        password: ["1234", "1234", "123456"],
        name: ['양땅우', '땡땡이', '곱창먹고싶다'] // 이 데이터는 말고, 위에만 받아오게 하고 싶다, 메서드를 변경하자
    }
  • 이제 API 쪽에서 모듈로 받아와 사용할수 있다
"use strict"
const UserStorage = require("../../models/UserStorage") // 가져오기
... 생략
const userStorage = new UserStorage(); // 스토리지 사용하기, 사실 인스턴스화 할필요는 없다, 

console.log(UseStorage) // 데이터만 쓸거면 바로 접근해도 상관없다
  • 하지만 바로 접근할려면 class가 변수를 사용할수있도록 static으로 선언해줘야한다
  • 하지만, 외부 에서 다이렉트로 접근하면 안되기 때문에 은닉화 해준다(#)

⇒ 그렇다면 조회는 해도, 사용은 어떻게해? undefined가 될텐데..?

⇒ 은닉화한 메서드로 은닉화한 변수를 불러오자

"use strict";

class UserStorage {
    static #users = { 
        id: ["양상우", "김개발", "박부장"],
        password: ["1234", "1234", "123456"],
        name: ['양땅우', '땡땡이', '곱창먹고싶다'] // 이 데이터는 말고, 위에만 받아오게 하고 싶다, 메서드를 변경하자
    }

    static getUsers(...fields) {  // 메서드를 이용해서 데이터를 사용가능하게 하자 // 이 메서드를 호출할때 user의 어디 부분까지 갈껀지, 즉 매개 변수를 정호가하게 잡을수 없으니, 호출할때 인자로 넘긴 변수들을 리스트로 받아와서
        const users = this.#users;
        const newUsers = fields.reduce((newUsers, field) => {  // 초기에 객체로 하거 newUser은 빈 오브젝트 -> id -> passwrod .. 이런식을 들어감 시작하면 필드로 들어 온 값이 할당 된다
            if (users.hasOwnProperty(field)) { // user에 해당하는 키값이 있으면 (예시로 id)
                newUsers[field] = users[field]
            }
            return newUsers // 다음 파라미터인 newUsers로 들어가게됨
        }, {});
        return newUsers // 마무리된 newUser
    }
}

module.exports = UserStorage;

고민해 봐야할거

  • 데이터 객체의 프로퍼티가 여러개 일텐데.. 메서드 매개변수 처리는 어떻게 해야하지?
  • 원하는 매개변수만 가져오고 싶은데

⇒ reduce+스프레드 문법으로 해결

home.ctrl

"use strict"
const UserStorage = require("../../models/UserStorage") // 가져오기

const output = {
    home: (req, res) => {
        res.render("./home/index") // views는 지정했기땨문
    },

    login: (req, res) => {
        res.render("./home/login")
    }
}

const procces = {
    login: (req, res) => {
        const id = req.body.id,
            password = req.body.password;

        //const userStorage = new UserStorage(); // 스토리지 사용하기, 사실 인스턴스화 할필요는 없다, 데이터만 쓸거면, 대신 해당 변수가 정적 변수여야 클래스에서  변수에 접근 가능하다
        const users = UserStorage.getUsers("id", "password")//하지만, 외부 에서 다이렉트로 접근하면 안되기 때문에 은닉화 해준다, 메서드로 불러온다
        const response = {}; // 깔끔하게 정리

        if (users.id.includes(id)) {
            const idx = users.id.indexOf(id);
            if (users.password[idx] === password) {
                response.success = true;
                return res.json(response);
            }
        }
        response.success = false;
        response.msg = "로그인에 실패하였습니다"
        return res.json(response)
    },
}

module.exports = {
    output,
    procces
};

🔚 돌아보기

구성

  • app라는 폴더에 소스코드를 몰아넣었고
  • app.js를 통해 node서버의 기본 설정을 하고
  • bin폴더에 실행파일
  • src에 mvc 패턴으로 분리 했다

좋은 웹페이지 즐겨찾기