240911 TIL - 대장간에도 발등에도 불이 났어요

LIHA·2024년 9월 11일
0

내일배움캠프

목록 보기
45/117
post-thumbnail

뼈대 짜기

회원가입 API

  • 유효성 체크 필요, 유효하지 않은 경우 HTTP 상태코드와 에러메시지 반환해야
  1. 필요한 정보를 입력받아 DB에 푸쉬해준다.
  2. 여기서 동일한 아이디를 가진 사용자가 있는지 프리즈마를 통해 DB에서 찾아보고 가입시킨다. where절로 아이디를 전달받아야 한다. findFirst 해도 되고 findUnique를 선택해도 된다. 다만 findUnique의 경우 unique인 컬럼이 없으면 에러가 난다고 수빈님이 조언해주셨다.
    -> 나는 발제 내용대로 id(계정아이디)에 unique를 걸어줬으므로 findUnique를 써도 괜찮았겠지만 일단 findFirst로 써줬다.

로그인 API

  • 아이디, 비밀번호로 로그인 요청
  • 계정정보 일치하지 않을 경우 알맞은 HTTP 상태코드와 에러메시지 반환해야
    -> ID가 존재하지 않는 경우
    -> ID는 존재하는데 비밀번호가 틀리는 경우
  • 로그인 성공 시 액세스 토큰 반환해줘야 함
    -> 이때 액세스 토큰의 payload에는 로그인 계정의 ID를 담고있어야 할것.
  1. sign-in 에서 중복아이디, 틀린비번 검증 후 다 통과하면 jwt.sign으로 만들어준다.
  2. 이때 jwt.sign에 accountId 넣고 .env의 시크릿키 넣고 expire 기간 걸어서 만든다.
  3. return절 res.status~ .json().json() 부분에 {message : "로그인 성공", data : accessToken } 이런 식으로 넣어서 반환해주면 된다.

캐릭터 생성 API (JWT 인증필요)

  • 캐릭터 명을 request에서 전달하고 response로 돌려받기
    -> 인증받지 않은 사용자가 게시글을 쓸 수 없게 하기 위해서 리퀘스트 헤더에 authorization 이라는 이름의 토큰이 필요하다는 것을 깔고 갈것임.
    -> 얘 왜인지 모르겠는데 Authorization이라고 쓰니까 못읽어옴. 그냥 authorization 이라고 써야할듯.
    -> 게시글 생성하고 비슷하게 갈것. JWT 인증되어야만 작성(생성) 가능
  1. 로그인 시 발급받은 Access Token 입력해주면 될것.
  2. 기본스탯 및 돈은 프리즈마 스키마 정의때 설정해놓은 것 있음.
  3. 로그인때 발급받은 토큰을 인섬니아 Auth에 집어넣을것
  4. 받는 것은 characterName 뿐이으로 얘를 const { characterName } = req.body; 로 받을것
  5. response로 돌려받기라는건 data : character 이런식으로 생성결과 같이 반환해주라는 얘기인것 같아 그렇게 구현.

캐릭터 상세조회 API

비로그인 / 로그인한 타인과 로그인한 캐릭터주인의 로직이 달라야한다.

캐릭터 삭제 API (JWT 인증필요)

일단 삭제할 캐릭터가 있는지부터 확인해야 한다. characterId를 req.params로 받아올 것.


트러블슈팅

passwordConfirm까지 DB에 저장될 필요가 있을까? DB에 들어가야 할 것들

과제에서 password를 제대로 입력했는지 한번 더 확인 입력받는 조건이 있어 아무 생각없이 passwordConfirm도 DB에 push하도록 했는데, 생각해보니 이건 클라이언트단에서 둘이 일치하는지만 걸러주고 가면 되고 DB에 저장될 필요까지는 없었다. 모두의 도움으로 불필요한 컬럼을 만들지 않도록 수정했다.

인증과 인가가 헷갈려 - Authentication과 Authorization

Authentication은 id, password로 로그인 하는 작업으로 볼 수 있다. 인증된 신분을 가진 사람인지 확인하는 것. OAuth도 이 중 하나.
Authorization은 인증된 신분인 것은 확인 했는데, 특정 리소스에 접근할 수 있는지 권한을 확인하는 것이다. 판다우리에는 강바오 송바오는 들어갈 수 있어도 나는 들어갈 수 없다. 로그인된 사용자만 게시글을 작성하도록 검증하는 과정이 인가이다. 이것은 사용자 인증 미들웨어로 구현할 것이다. -> 이게 auth.middleware.js!

bcrypt 복호화도 가능은(?) 하다 - bcrypt.compare를 통해 비교할 수 있다

bcrypt.compare(입력받은 pwd, prisma find로 찾은 DB의 해당계정 pwd) 이렇게 써서 복호화 한 결과가 같으면 true, 아니면 false로 돌려줄 것이다.

이런 식으로 짠다.

로그인에 성공하면 토큰을 준다구요? 왜요?

토큰을 '쿠키에 담아 전달하지 말라'는 것 뿐이지, 토큰은 어찌됐든 줘야한다. 그래야 어떤 작업을 수행할 때 '내가 이 계정으로 로그인 한 이 사용자야!' 라는 것을 매번마다 서버가 알고 이 리퀘스트 주체의 행동을 인가할지 말지 결정할 수 있기 때문!
-> 로그인은 인증, 한정 리소스에 접근하는 것은 인가. 그래서 JWT도 인증을 위한 과정이다.
나중에 게시판 유저, 관리자 등의 등급과 접근권한을 나눈다면 그건 별도의 '인가'가 될것.

JWT는 토큰 암호화를 위한 시크릿 키가 필요하다 - .env에 감춰놓자

내가 여기에 TOKEN_SECRETKEY를 .env에 따로 빼놓고 dotenv로 불러온 이유는, JWT 암호화 할때 저 시크릿키가 필요하기 때문.

JWT가 Bearer 형식인 것은 만들 때 Bearer를 붙여줘야 한다

튜터님은 쿠키를 쓰셨지만 일단 형태만 보자면, req에 쿠키를 할당해주고 있다. 'authorization'이라는 키 값을 가지고 Bearer로 시작하도록 Bearer ${token} 이라는 형태로 조립해주었다.

Bearer는 JWT의 프로토콜 -> '얘는 JWT를 사용해서 인증요청 하는거야' 라는 것을 알려주는 용도. 얘가 붙어서 나가는 것은 내가 Insomnia의 Auth에서 Bearer Token을 선택했기 때문이고, jwt.sign만 하면 헤더.페이로드.시그니처인 알몸(?)만 뿅 만들어지는게 맞다.
내가 얘를 Bearer 형식으로 보내는 토큰임을 알리려는 방법은 여러가지다. Headers에 Add 해서 Bearer%20 만큼을 붙여줘서 만들어도 상관없는 것.

Access Token, Refresh Token이 그래서 뭐였더라?

240910 TIL 참고해볼 것.

Access Token이 내가 처음에 로그인 할때 발급받았던 그 토큰이 맞다. 그런데 걔가 탈취되면 곤란하니(로그인에 필요한 일종의 키가 아예 털려버리니까),

Access Token 시간을 짧게 주고 Refresh Token을 길게 주는 식으로 털려도 덜 위험하도록 계속 인증 인가를 다시 하게 만들자는 시스템.

그래서 리프레시 토큰은 어떻게 만드는데? -> 이건 지금은 필요없지만, 액세스 토큰 만들듯 시크릿키 따로 두고 jwt.sign으로 만들면 된다.

res.header에 'Authorization'으로 보냈는데 req.headers에 'authorization' 으로 들어서 온다?

얘는 왜 이렇게 오는걸까? 이유는 모르겠지만 req.headers['authorization'] 으로 바꿨더니 잘 찾는다. 얘는 그냥 둬야겠다.

req.user? -> 인증 미들웨어에 있다

Authorization Header에 담은 JWT를 토대로 사용자를 인식하는 녀석이고 검증절차도 auth.middlewares.js에 다 들어있다. 계정의 고유 id로 유저를 찾고, 찾았으면 그 정보를 req.user에 담아서 다음 미들웨어로 넘겨준다.

그게 요 부분이다. req.user = user 이 구절이 검색된 유저정보를 req.user에 담는거고, next()로 다음 미들웨어에 넘기고 있다.

위 얘기가 저 req.user 얘기다. 나는 JWT 기반으로 인증된 사용자 정보를 이미 담아서 다음 동작으로 넘기고 있으니 OK.

비로그인이 auth 미들웨어에서 걸린다 - 다른 미들웨어를 만들고 미들웨어를 건너뛰게 하자

캐릭터 상세조회에서 다른유저 로그인까진 되는데, 비로그인 유저의 경우 auth 미들웨어에서 토큰이 없다고 걸려버려 아무리 if문을 걸어도 캐릭터 조회 로직은 타지도 못한다.

어떻게 해야할지 도저히 감이 안 와 질문드리러 총총.

  • 정섭튜터님의 말씀

여기는 auth미들웨어가 오면 안되거나, 다른 미들웨어가 필요할 수 있다. 아니면 다른 미들웨어가 필요한건 맞는데, auth 미들웨어도 있으면 auth 미들웨어 까지 실행하지는 않을 수 있는 방법이 있다.

1. 요주는 auth미들웨어 앞에 분기 같은게 걸리면 되는 것! auth 헤더를 검증해서 헤더에 토큰이 없으면 없는대로 새 미들웨어쪽 로직을 타고, 있으면 auth 미들웨어를 타게끔.

  1. 익스프레스 미들웨어 문서를 보면 미들웨어를 건너뛰는 방법에 대해 나와있다. next('route') 를 쓰면 이 핸들러의 다음 경로로 가는게 아니라 다음 라우터로 점프해버린다.
    (이걸 모른다면 익스프레스 문서를 안읽은 것😏)
    익스프레스 문서
    미들웨어 건너뛰는 방법 긱

  2. 아니면 req에서 값을 하나 더 설정할 수도 있을 것이다. req.isSignedUser 같은 불린값을 설정해 보는것도... -> ?? 이 말씀은 잘 이해하지 못했다😥

그래서 방법은 크게 두가지!
1. auth미들웨어를 고친다
2. 다른 미들웨어를 추가해야 한다
근데 1번은 부작용이 크니까 다른 미들웨어를 추가하는게 좋다.

그렇게 고친 나의 코드는 다음과 같다

얘를 characters.router.js에 import 해주고 캐릭터 상세조회 라우터에 미들웨어로 끼워넣었더니 원하는 대로 동작한다!

PUT과 PATCH의 차이 - PUT은 전체수정, PATCH는 부분수정

참고 블로그

  • 항상 헷갈리는 PUT과 PATCH. 게임을 긴급패치 한다고 하지 긴급풋 한다고 안 한다. 이것을 기억해보자.

PUT : 자원의 전체 교체, 자원교체 시 모든 필드 필요
(만약 전체가 아닌 일부만 전달할 경우, 
전달한 필드외 모두 null or 초기값 처리되니 주의!!)
PATCH : 자원의 부분 교체, 자원교체시 일부 필드 필요

Prisma query에서 Json 타입으로 선언할 수 있다!

이런 식으로 item_stat을 Json 타입으로 선언하면 item_stat : {"atk" : item_stat.atk, "hp" : item_stat.hp} 이런 식으로 써줄 수 있다. 한 개의 컬럼에서 여러 데이터를 다룰 수 있는 것.

커밋 컨벤션은 어떻게? 패키지 매니저 같은 것은 chore로

참고 블로그

chore는 하기 싫은 일, 혹은 루틴적으로 하는 일이라는 뉘앙스가 담겨있다. (집안일 같은 느낌)

feat : 새로운 기능 추가
fix : 버그 수정
docs : 문서 수정
style : 코드 포맷팅, 세미콜론 누락, 코드 변경이 없는 경우
refactor : 코드 리펙토링
test : 테스트 코드, 리펙토링 테스트 코드 추가
chore : 빌드 업무 수정, 패키지 매니저 수정


번외

새벽 2시인데 대체 언제 자러가요

제발 집에 가염 여러분

profile
갑자기 왜 춤춰?

0개의 댓글