TiL#27. 개인과제 2일차

깡통·2024년 1월 30일
0

  • 인증 절차를 통과하면 jwt객체의 sign메서드를 활용해서 인증 정보가 담긴 토큰을 발급함.

  • 해당 토큰 정보를 Bearer 방식으로 묶어 'authorization'이라는 이름의 쿠키에 저장해 response를 보냄

  • 1차 수정

-jwt.sign({}) 안에는 로그인에 필요한 정보가 들어가야 함
-app.js 에 /career 기본 경로가 지정돼있는데, 한번 더 써서 404 에러가 떴었던 거임
('/career/signIn'이 아니라 '/signIn'이었어야 함.)


  const accessToken = 
  <Header>
  jwt.sign(
  
  <Payload>
    {
      userId: user.userId,
      email: user.email,
      password: user.password,
    },
    
    <Signature>
    ACCESS_TOKEN_SECRET_KEY,
    { expiresIn: '12h' }
  );

  res.cookie('accessToken', accessToken);
  • 첫번째

  • 이제 제대로 되네
accessToken	
<Header - 토큰의 타입, 어떤 암호화를 사용해 생성된 데이터인지 정의>
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
<Payload: Data,실제 전달하려는 데이터>
eyJ1c2VySWQiOjMsImVtYWlsIjoibWlsa0BuYXZlci5jb20iLCJwYXNzd29yZCI6InBhc3N3b3JkIiwiaWF0IjoxNzA2NjI2NDAzLCJleHAiOjE3MDY2Njk2MDN9.
<Verify Signature - 헤더, 페이로드, 비밀키를 이용해 생성됨/토큰 변조여부 확인>
AJd-yVAXO8YtvovLzv6Lff_bH6xVMpsi_eOM29WNmTc

  • 생각해보니 객체는 index가 명확하지 않고, 대신 프로퍼티의 key로 찾잖아. 근데 내가 지금 쿠키를 생성할 때 key를 accessToken으로 줬는데, authorization key를 가진 프로퍼티를 찾아서 구조분해할당을 하라는 식으로 코딩을 짠거 같은데, 그래서 문제가 생기는거 아닐까?

    • 맞네 ㅡㅡ;; 아 어지럽다.
  • auth.middleware.js 완성된 코드

  • 이중 셀렉트 문법

-이중 셀렉트 문법처럼 객체의 객체 프로퍼티를 받는 식으로 해볼랬는데 잘안댐

-그래서 요렇게 고쳤는데(위에 api 내부에 userInfos 인스턴스를 불러들이는 코드 있음), auth middleware를 보니까 딱히 필요없는거 같음

  • 이미 authMiddleware를 통해서 인증을 하고 넘어오기 떄문에 따로 where를 쓸 필요 없음. 그리고 create메서드에서는 where 명령어를 쓸 수 없는듯 함(에러뜸)
  • 이력서 수정 api

  • const resume = await prisma.resume.findfirst({})라서 그냥 resume.update 하면 먹힐 줄 알았는데 안먹힘

  • 이력서 삭제 api

  • 비밀번호 검사 절차를 한번 더 거치게 해서 삭제하는 api를 구현하고 있는데, 이 에러는 멀까?

  • req 한번에 res 한번이 국룰인데, 나는 req한번에 res를 두번이나 보내려고 했음, 그래서 문제가 생겼던 거임

  • 원래는 자바스크립트에서(그러니까 프론트엔드) 이벤트를 발생시켜서 처리한 뒤에 삭제만 서버로 넘겨서 하는 거라고 함.

  • 근데 일단 가능은 할 거 같으니 조져보겠음 ㅅㅅ

  • 결론

  • 그렇다고 한다... ㅠ

  • 사용자 : 이력서 = 1: N 관계 구현 중

  • resume에 @unique 넣으니까 1대1 관계 돼버림, 빼야하는 듯

  • npx prisma migrate dev << schema 수정하고 prisma orm migrate 함

  • 그러니까 raw query 형태로 migrations 폴더가 생성됨

  • 오 작동 잘됨, 굳!

  • queryString 적용

  • queryString 코드를 vsc 작성 단계에서 쓰는게 아니고, 이건 url에 직접 치는 거고 직접 쳐놓은 queryString을 처리하는 로직을 라우터 안에 구축해야 함

  • 모든 이력서 목록 조회 API

  • orderKey의 userId를 읽지 못하고 있음.

  • refresh Token의 목적은 사용자가 인증 기능이 필요해 accessToken을 사용해야 하는 api를 추가적인 로그인 절차 없이(왜냐면 보안을 위해 accessToken은 수명이 짧으니까) 이용할 수 있게끔 해주는 기믹임. 그래서 로그인 할때 refresh Token과 access Token을 함께 발급 받는 것

  • users.router.js

import jwt from 'jsonwebtoken';
import { prisma } from '../utils/prisma/index.js';
import dotenv from 'dotenv';

dotenv.config();

const ACCESS_TOKEN_SECRET_KEY = process.env.ACCESS_TOKEN_SECRET_KEY;
const REFRESH_TOKEN_SECRET_KEY = process.env.REFRESH_TOKEN_SECRET_KEY;

//사용자 인증 미들웨어는 express 의존성이 존재하지 않는다고 함. 무슨 의미인지는 아직 잘 모름
export default async function (req, res, next) {
  try {
    //발급받은 cookies의 첫번째 프로퍼티를 객체분해할당으로 authorization 식별자에 할당해서 추출함

    const { accessToken, refreshToken } = req.cookies;

    function validateToken(token, secretKey) {
      try {
        return jwt.verify(token, secretKey);
      } catch (error) {
        console.error(error);
        return null;
      }
    }
    const decodedToken = validateToken(accessToken, ACCESS_TOKEN_SECRET_KEY);

    if (decodedToken) {
      //user.router.js의 로그인API에서 생성되어 넘어온 cookies의 userId 정보가 userId 상수에 할당됨
      const userId = decodedToken.userId;

      if (!userId) throw new Error('로그인을 해주세요!');
      //그리고 그 userId와 일치하는 userId를 가진 user를 찾아냄
      const user = await prisma.users.findFirst({
        where: {
          userId: +userId,
        },
      });
      const userInfo = await prisma.userInfos.findFirst({
        where: {
          userId: +userId,
        },
      });
      if (!user) throw new Error('토큰 사용자가 존재하지 않습니다.');
      //이후로 미들웨어에서 req를 통해 전달되는 모든 user는 바로 decodedToken을 타고 와 모든 인증을 거친 userId를 가진 user임
      req.user = user;
      req.userInfo = userInfo;
      next();
    }
    //accessToken이 존재하지 않거나, 유효하지 않은 경우 refreshToken을 사용해 재발급 받아야 함
    else if (!accessToken || !decodedToken) {
      //refreshToken  검증
      //1. refreshToken의 존재 여부 검증
      if (!refreshToken) {
        return res
          .status(400)
          .json({ errorMessage: 'refresh Token이 존재하지 않습니다.' });
      }

      //2. refreshToken이 존재한다면, 유효여부 검증
      const verifiedRefreshToken = validateToken(
        refreshToken,
        REFRESH_TOKEN_SECRET_KEY
      );
      if (!verifiedRefreshToken) {
        return res
          .status(401)
          .json({ errorMessage: 'refresh Token이 유효하지 않습니다.' });
      }

      //3. tokenStorage[refreshToken] 정보가 있는지 여부 확인(어떻게 가져오지...)
      //미들웨어에 토큰 스토리지를 들고 오면 안댐(개인정보가 공통적으로 사용되는 미들웨어 상에서 노출돼버림), 필요하면 클라이언트에게 다시 요청하던가, 아니면 그냥 안해야 됨
      //accesstoken과 refreshtoken 안에 있는 유저 아이디로 데이터베이스 안에 있는 유저 정보를 가져오도록 설계해야 함
      // const userInformation = tokenStorage[refreshToken];
      // if (!userInformation)
      //   return res.status(419).json({
      //     errorMessage: 'refresh Token의 정보가 서버에 존재하지 않습니다.',
      //   });

      //refreshToken은 이미 jwt 문자열이라서 newAccessToken은 찍어봤자 아무것도 안나옴
      //jwt.verify >> 인증기능만 있는 줄 알았는데 복호화 기능이 같이 있었다!
      const newAccessToken = jwt.sign(
        {
          userId: verifiedRefreshToken.userId,
          email: verifiedRefreshToken.email,
          password: verifiedRefreshToken.password,
        },
        ACCESS_TOKEN_SECRET_KEY,
        { expiresIn: '10s' }
      );

      //user.router.js의 로그인API에서 생성되어 넘어온 cookies의 userId 정보가 userId 상수에 할당됨
      const userId = jwt.verify(newAccessToken, ACCESS_TOKEN_SECRET_KEY).userId;

      if (!userId) throw new Error('로그인을 해주세요!');
      //그리고 그 userId와 일치하는 userId를 가진 user를 찾아냄
      const user = await prisma.users.findFirst({
        where: {
          userId: +userId,
        },
      });
      const userInfo = await prisma.userInfos.findFirst({
        where: {
          userId: +userId,
        },
      });
      if (!user) throw new Error('토큰 사용자가 존재하지 않습니다.');
      //이후로 미들웨어에서 req를 통해 전달되는 모든 user는 바로 decodedToken을 타고 와 모든 인증을 거친 userId를 가진 user임
      req.user = user;
      req.userInfo = userInfo;
      next();
    }
  } catch (error) {
    console.error(error);
    res.status(404).json({ message: error.name });
  }
}

  • jwt.verify()는 인증 말고도 복호화 기능이 있다, 참고.
  • jwt.sign()을 통해 jwt문자열로 만들어서 cookie에 담아 전달한 애들은 복호화 전까지는 아무 기능이 없는 문자열이다.
profile
코딩하러 온 사람입니다.

0개의 댓글