Authentication 구축하기
크게 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에 관한 유저를 식별하는 기능은 아직 없으니 강의를 보고 추가해줘야겠다.