작은 도서관
article thumbnail

셀프 레퍼런스

https://flreauniverse.tistory.com/26 (세션과 토큰)

개요

  • 유저 스키마와 모델 생성하기
  • 유저 crud 구현하기
  • 로그인 api를 연결하고 토큰 발급하기
  • 토큰 검증하기
  • api 테스트하기
  • (번외) 비밀번호 암호화

유저 스키마와 모델 생성하기

스키마와 모델 생성은 지난 시간에 해본 적 있습니다.

실력을 더욱 키우고 싶다면 아래 코드를 보지 말고 한번 짜보는것도 좋은 방법입니다.

 

유저에 필요한 값은 생각보다 간단합니다.

이 두가지 값을 코드로 옮겨보겠습니다.

model 폴더 아래에 user.js 파일을 만든 뒤 아래 코드를 작성해주세요.

import mongoose from "mongoose";

const userSchema = new mongoose.Schema({
  username: { type : String, required: true, unique: true },
  password: { type : String, required: true },
},
{
  timestamps: true,
});

export default mongoose.model('User', userSchema);

username에 unique라는 속성을 넣었기 때문에, 이미 저장된 아이디로는 유저 데이터를 생성할 수 없게 되었습니다.

유저 CRUD 생성하기

라우터 파일을 하나 새로 만들겠습니다.

router 폴더 아래에 user.js 파일을 생성해주세요.

import express from 'express';
import User from '../model/user.js'

const userRouter = express.Router();

userRouter.post("/", async (req, res) => {
  const data = req.body;
  console.log(data);
  const username = data.username;
  const password = data.password;
  const user = new User({
    username: username,
    password: password,
  })
  await user.save();
  res.send("데이터가 생성되었습니다.");
});

userRouter.get("/", async (req, res) => {
  const data = await User.find();
  res.send(data);
});

userRouter.get("/:id", async (req, res) => {
  const data = await User.findById(req.params.id);
  res.send(data);
});

userRouter.patch("/:id", async (req, res) => {
  const data = await User.findByIdAndUpdate(req.params.id, req.body);
  res.send(data);
});

userRouter.delete("/:id", async (req, res) => {
  const data = await User.findByIdAndDelete(req.params.id);
  res.send(data);
});

export default userRouter;

저번 postRouter를 복붙한 후, 일부 내용만 수정했습니다.

잊지 말고 index.js 파일에도 라우터를 추가해주세요.

import userRouter from './router/user.js';

...
app.use("/user", userRouter);
...

로그인 api를 연결하고 토큰 발급하기

로그인 api는 POST /login URL을 사용합니다.

router 폴더 아래에 auth.js 파일을 만들어주세요.

yarn add jsontokenweb

 

import express from 'express';
import jwt from "jsonwebtoken";
import User from '../model/user.js';

const authRouter = express.Router();

authRouter.post("/login", async (req, res) => {
  const key = "1234qwer";
  const data = req.data;
  const username = data.username;
  const password = data.password;

  const user = await User.findOne({ username: username });
  if (!user) {
    res.send("사용자를 찾을 수 없습니다.")
  }
  if (user.password !== password) {
    res.send("비밀번호가 틀립니다.");
  }

  const token = jwt.sign(
    {
      type: "JWT",
      id: user._id,
      username: username,
    },
    key,
    {
      expiresIn: "30m", // 토큰의 유효 기간입니다. 원하는대로 조절하면 됩니다.
    },
  );

  res.send(token);
})

export default authRouter;

nodejs 라이브러리인 jsonwebtoken을 사용합니다.

request로 username과 password를 받아와서 이를 Key로 암호화 한 뒤 돌려보내는 jwt의 함수 sign을 사용합니다.

sign은 인자 세개로, 토큰의 내용, 암호화 키, 토큰의 옵션을 받습니다.

클라이언트에선 받은 토큰을 헤더에 등록하여 사용하면 됩니다.

 

암호화 키는 환경변수로 분리해줍시다.

TOKEN_SECRET=1234qwer

.env 파일에 추가해줍니다.

./src/router/auth.js

...
const key = process.env.TOKEN_SECRET;
...

라우터에서도 수정해주면 됩니다.

마지막으로 index.js 파일에도 추가해줍니다.

import authRouter from './router/auth.js';

...
app.use("/auth", authRouter);

토큰 검증하기

클라이언트가 토큰을 쿠키에 등록해 서버에 요청을 보냈을 때, 토큰이 유효한지 검증하는 미들웨어를 작성하겠습니다.

src 폴더 아래에 middleware 폴더를 만들고, 그 안에 다시 auth.js 파일을 만들어주세요.

import jwt from 'jsonwebtoken';

const verifyToken = (req, res, next) => {
  const token = req.headers.authorization;
  try {
    const user = jwt.verify(token, process.env.TOKEN_SECRET);
    req.user = user;
    return next();
  } catch (err) {
    return res.send("올바르지 못한 요청입니다.");
  }
}

export default verifyToken;

이제 이 미들웨어를 사용해 보겠습니다.

유저 정보를 조회할 때 조건이 있습니다.

1. 로그인이 되어있어야 하고,

2. 본인의 정보여야 합니다.

// ./src/router/user.js
...
userRouter.get("/:id", verifyToken, async (req, res) => {
  if (req.user.id !== req.params.id) {
    res.send("권한이 없습니다.");
  }
  const data = await User.findById(req.params.id);
  res.send(data);
});
...

따라서 위와 같이 코드를 짤 수 있습니다.

api 테스트하기

사용자 생성-토큰 발급-사용자 정보 조회(성공/실패)까지 api테스트를 해보겠습니다.

가장 먼저, POST localhost:8000/user 요청입니다.

사용자 생성이 제대로 된 걸 확인 후, POST localhost:8000/auth/login 테스트를 진행합니다.

응답으로 받은 문자열을 Headers에 authorization으로 등록합니다.

이제 GET localhost:8000/user/:id에 로그인한 본인이 아닌 다른 정보를 요청하면 다음과 같은 응답을 얻습니다.

올바를 경우, 사용자의 정보를 받아올 수 있습니다.

오늘의 파일구조

profile

작은 도서관

@Flrea

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!