Project/트윗 클론코딩

Authentication 구축하기

CoderHan 2023. 9. 30. 19:27
반응형

크게 Auth에 관한 내용을 처리할 때 쿠키&세션을 활용하는 방법과 JWT를 사용하는 방법이 있다.

이 둘엔 장단점과 차이점이 있는데 이에 관한 포스팅은 전에 올린 적이 있으니

아래 글에서 확인하면 좋을 것같다.

 

우리 트윗 클론코딩은 브라우저만 상대하는 게 아닌 여러 클라이언트를 상대하는

RESTful API를 사용하고 세션의 정보를 얻기 위해 하나의 db에 접속할 필요가 없고

확장성을 확보하기 위해 JWT를 사용하도록 결정했다.

 

요청 메소드 req res 비고
/auth/signin POST {id : text, pw : text} {jwt : jwt, username : text} / 200  
/auth/signup POST {id :text,
pw : text,
username : text,
name : text,
email : email,
url : url}
201  

이런식으로 API를 사용하면 되지 싶은데 강의에선 어떻게 했는지 아래에 또 적어보겠다

---------------------------------------------------------------------------------------------------------------

 

Auth

User Schema

 id: string // 사용자의 고유한 아이디

username: string, // 사용자 닉네임 (아이디)

password: string, // 사용자 비밀번호

name: string, // 사용자 이름

email: string, // 사용자 이메일

url: string (optional) // 사용자 프로파일 사진 URL }

 

주소 메소드 req res 비고
/auth/signup POST {username,
password,
name,
email,
url
}
{token,
username}
 
/auth/login POST {username,
password}
{token,
username}
 
/auth/me GET   {token,
username}
 

 

나는 내가 흔히 쓰는 id를 스키마에서 똑같이 썼는데

db에서 고유하게 식별가능한 id와 사용자가 로그인 할 때 쓰는 id(username)을 다르게

가져가야 한다는 점을 내가 간과했던 것 같다.

그리고 /me는 백엔드에서 사용자가 token을 가지고 있는지 확인 할때 쓰는 용도라고 배웠다

이제 이를 적용해서 로그인도 구현해보자

 

 

앞서 모델 뷰 컨트롤러 패턴으로 구현했기 때문에 로그인도 비슷하게 구현해보겠다.

import express from "express";
import { body } from "express-validator";
import { loginTweet, signUpTweet } from "../data/auth.js";

const router = express.Router();

router.post(
  "/login",
  [
    body("username").trim().notEmpty("이름을 확인해주세요"),
    body("password")
      .isLength({ min: 2, max: 500 })
      .withMessage("최소 2글자 이상 입력해야 합니다"),
  ],
  loginTweet
);
router.post(
  "/signup",
  [
    body("username").trim().notEmpty("ID를 입력해주세요"),
    body("password")
      .isLength({ min: 2, max: 500 })
      .withMessage("최소 2글자 이상 입력해야 합니다"),
    body("name").trim().notEmpty("이름을 입력해주세요"),
    body("email")
      .trim()
      .notEmpty("이메일을 입력해주세요")
      .isEmail()
      .withMessage("형식에 맞게 입력해주세요"),
  ],
  signUpTweet
);
router.get("/me");

내가 구현한 authRouter인데 /me에 관한 부분은 어떻게 처리해야 할 지 몰라서 남겨놨다.

그리고 컨트롤러로 넘어가기 전에 validation으로 불필요한 요청을 컷트해내는 코드를 적어놨다.

 

import { loginTweet, signUpTweet } from "../data/auth.js";

export function login(req, res, next) {
  const id = req.body.id;
  const password = req.body.password;

  const user = loginTweet(id, password);
  if (user) {
    res.status(200).json(user);
  } else {
    res.status(404).json();
  }
}

export function signUp(req, res, next) {
  const user = signUpTweet(req.body);
  if (user) {
    res.status(200).json(user);
  } else {
    res.status(404).json({ message: "ID 혹은 Password가 일치하지 않습니다" });
  }
}

export function me(req, res) {
  const user = verifyUser();
  if (user) {
    res.status(200).json(user);
  } else {
    res.status(404).json();
  }
}

여긴 컨트롤러 부분인데 라우터에서 검증을 거쳤으므로 얻은 데이터를 직접적으로 기능을 수행하는 함수에 연결한다

여기서 검증을 한 번 더 거치는 단계를 추가하면 더욱 견고한 코드가 되겠다..라는 생각을 해본다..

 

let users = [
  {
    id: 1,
    username: "doyun",
    password: "1234",
    name: "Doyun",
    email: "dy__z@nate.com",
    url: "",
  },
];

export function loginTweet(id, password) {
  const user = users.find((e) => e.username == id && e.password == password);
  if (user) {
    return { token, username };
  }
}

export function signUpTweet(data) {
  const { username, password, name, email, url } = data;
  const user = {
    id: new Date().toString(),
    username,
    password,
    name,
    email,
    url,
  };
  users.push(user);
  return { token, username };
}

여기가 data영역이다

전달받은 id와 pw가 일치하면 토큰과 유저네임을 리턴한다.

회원가입도 id를 생성하고 토큰을 리턴해준다.

/me에 관한 유저를 식별하는 기능은 아직 없으니 강의를 보고 추가해줘야겠다.

반응형