2024.05.09(목) 슈퍼코딩 부트캠프 신입연수원 WEEK 2 Day 4 일일보고

usnim·2024년 5월 9일
0

super_coding

목록 보기
9/35

📋 TO-DO LIST

신입 연수원 활동 [o]

2주 4일차 강의 [o]

인턴교육 직후 사수 도움 요청 업무 [o]

팀장님 지시 업무 [o]

중간/일일 업무 보고 작성 [o]

정기 팀/동기 스터디 모임 참석 및 성실도 [o]

📍 학습 내용 정리

번들러

번들러란?

번들러는 여러 개의 파일로 분할된 코드를 하나의 파일로 묶어주는 도구입니다.

이를 통해 모듈화된 코드를 쉽게 관리하고, 웹 페이지의 성능을 향상시킬 수 있습니다.

또한, 번들러는 모듈 간의 의존성을 해결하고, 필요한 모듈만 로드하여 불필요한 네트워크 요청을 줄여줍니다.

이를 통해 애플리케이션의 초기 로딩 시간을 단축하고 성능을 최적화할 수 있습니다.

번들러의 기능

병합(Merging)과 최소화(Minification): 번들러는 여러 개의 파일을 하나로 병합하여 네트워크 요청을 줄여줍니다.

또한, 코드를 최소화하여 파일 크기를 줄일 수 있습니다.

모듈 시스템 지원: 번들러를 이용하면 CommonJS, AMD와 같은 모듈 시스템을 브라우저에서 사용할 수 있습니다.

이는 코드의 재사용성과 유지보수성을 높여줍니다.

트랜스파일링 지원: 번들러는 Babel과 같은 트랜스파일러를 이용하여 최신 자바스크립트 문법을 브라우저 호환 가능한 코드로 변환할 수 있습니다.

이로써 개발자는 최신 문법을 사용하면서도 다양한 브라우저와 호환성을 유지할 수 있습니다.

환경 변수 처리, 파일 경로 관리: 번들러를 사용하면 환경 변수를 관리하거나, 파일 경로를 절대 경로로 관리하는 등의 추가적인 기능을 활용할 수 있습니다.

웹 프레임워크

웹 프레임워크란?

웹 프레임워크는 웹 개발 프로세스의 일부 측면을 자동화하여 더 쉽고 빠르게 만들 수 있는 소프트웨어 도구입니다.

즉, 웹사이트, 웹 업플리케이션, 모바일 앱 또는 소프트웨어의 아키텍처를 구축하는데 도움이되는 모델 및 라이브러리 입니다.

더 자세하게 설명하자면 사용자 인터페이스 / 비즈니스 규칙 / 데이터 모델을 분리하여 웹 페이지 개발 하는 과정에서 DB연동 및 HTML템플릿 양식, Session, 코드 재사용 등의 개발자의 번거로움이 들어가는 부분들을 해결해 주며 여러 기능들을 제공합니다.

프레임워크 & 라이브러리

라이브러리와 프레임워크는 프로젝트를 개발하는데 있어 기능을 제공해주고 개발자에게 편리함을 공통점이 있습니다.

라이브러리 : 우리가 개발하려는 모듈이나 프로젝트에 적합한 기능을 제공합니다.

프레임워크 : 물론 적합한 기능을 제공해주는 역할도 있지만 그것보다 하나의 완성된 안전한 프로젝트 구조에 맞는 틀,

패키지를 제공해주는 것입니다.

쉽게 말하면 라이브러리는 우리 입맛에 맞게 사용하는 기능이라면
프레임워크는 우리가 그 구조나 패키지에 맞게 개발을 해야한다는 것입니다.

Web Framework 장점

서비스를 구현하는데 패키지 및 모듈을 제공하여 프로그래밍의 간편함과 속도를 높여줄 뿐만아니라 어떤 개발자라도 프로그래밍하는데 있어 필요하지만 매번 하는 공통적인 작업들을 일괄적으로 처리해주며 그 부분에 신경을 덜 쓸 수 있게 합니다. 또한 개발 중에 발생한 오류등을 쉽게 찾을 수 있는 디버깅이나 테스트를 제공하여 오로지 어플리케이션 로직에 더 신경 쓸 수 있는 장점이 있습니다.

보안 : 프레임워크는 여러 관점에서 보안을 제공합니다. 외부 공격 및 문제,
충돌 속도 저하 및 기타 부정적인 측면으로부터의 보안해주며 어플리케이션의 품질이 저하될 수 있는 경우를 줄여줍니다.

확장성 : 프레임워크는 매우 유연합니다. 간단한 소프트웨어 도구에서 복잡한 도구까지 웹 어플리케이션을 구축할 때 동일한 프레임워크를 사용할 수 있다.

Session & JWT

세션(Session)?

세션은 브라우저와 웹 서버가 연결되어 브라우저가 종료될 때까지의 시점입니다. 브라우저를 통해 서버에 접속할 때 서버는 세션 id를 쿠키에 담아 되돌려주고, 사용자는 세션 id를 담은 쿠키인 세션 쿠키를 이 후 요청부터 계속해서 함께 전달함으로 서버가 클라이언트를 식별할 수 있게 하는 기술이 세션 기반 인증 방식인데 보통 세션이라고 합니다.

클라이언트가 HTTP요청을 보낼 때 쿠키에 세션 id가 없다면 서버는 세션 id를 생성 해 쿠키에 담아서 돌려줍니다. 다시 HTTP 재요청을 할 때 쿠키를 보내기 때문에 서버에서는 세션 id를 통해 클라이언트를 식별할 수 있습니다.

JWT(JSON Web Token)

https://velog.io/@baby_back-dev/2024.05.08%EC%88%98-%EC%8A%88%ED%8D%BC%EC%BD%94%EB%94%A9-%EB%B6%80%ED%8A%B8%EC%BA%A0%ED%94%84-%EC%8B%A0%EC%9E%85%EC%97%B0%EC%88%98%EC%9B%90-WEEK-2-Day-3-%EC%9D%BC%EC%9D%BC%EB%B3%B4%EA%B3%A0

Session vs JWT

세션방식에서 서버는 로그인 된 유저의 정보를 모두 저장하고 있어서 유저들의 통제가 JWT보다 비교적 쉽습니다. 만약 PC와 모바일기기에서 동시 접근하는 것을 막고 싶을 때 강제 로그아웃 시키는 기능은 세션을 통해 구현이 가능합니다.

JWT를 서버가 발급하고나면 JWT를 관리하지 않습니다. 오직 JWT를 받았을 때 JWT가 유효한 것인지만 확인하기 때문에 서버 자원과 비용을 절감할 수 있습니다. 그러나 JWT가 수명이 길어서 제 3자에게 탈취당할 경우가 발생할 수 있습니다. 이를 보완한 방법 중 하나로 access token & refresh token 방식이 있는데 두개의 토큰 모두 JWT입니다.

access token과 refresh token 관련된 것도 위 링크 정리해뒀습니다.

📍 일일보고

부족한 점 : 라이브러리나 내장함수에 대한 이해력 부족

스스로 시도해본 것들 : 로그인 후 refresh_token을 DB에 저장하고 access_token과 refresh_token을 반환하는 로직과 http 요청할 때 refresh_token을 담아 DB에 refresh_token과 검증하고 같다면 새로운 access_token을 반환하는 로직을 구현

# post method
@app.post('/login')
async def login_user(email:str,password:str):
  user = collection.find_one({"email":email})
  if user is None or user["password"] != await hash_password(password):
        raise HTTPException(status_code=401, detail="인증 실패: 이메일 또는 비밀번호가 올바르지 않습니다.")
  user_id = str(user["_id"])  # 사용자 ID를 문자열로 변환
  access_token = await generateJWT(email, user_id)
  refresh_token = await generateRefreshToken(email, user_id)
  
  add_refresh_token = collection.update_one({"_id": user["_id"]}, {"$set": {"refresh_token": refresh_token}})
  
  print(add_refresh_token)
  
  return {"user_id": user_id, "token": access_token , "refresh_token": refresh_token}

@app.post('/refresh_token')
async def refresh_token(refresh_token:str):
  is_valid_refresh_token = collection.find_one({"refresh_token":refresh_token})
  if is_valid_refresh_token is None:
    raise HTTPException(status_code=401, detail="Refresh token이 유효하지 않습니다.")
  email ,user_id = await decode_refresh_token(refresh_token)
  
  access_token = await generateJWT(email, user_id)
  
  return {"token": access_token}

access_token을 쿠키에 담아 "/protected"에서 쿠키에서 access_token을 받아와 검증해 token안에 있는 정보들을 반환하는 로직 구현

from fastapi import FastAPI , Query , HTTPException , Request,Response,Cookie
from pydantic import BaseModel
from typing import List
from fastapi.staticfiles import StaticFiles
from pymongo import MongoClient
from bson import ObjectId 
import json
import hashlib
import jwt
import datetime

async def hash_password(password):
  return hashlib.sha256(password.encode()).hexdigest()

async def generateJWT(email , user_id):
  # 현재 시간을 UTC 기준으로 가져오기
  now_utc = datetime.datetime.now(datetime.timezone.utc)
  
  # 만료 시간 설정 (현재 시간에서 1주일 후로 설정)
  expiration_time = now_utc + datetime.timedelta(hours=1)
  payload = {
    "email" : email,
    "user_id" : user_id,
    "exp": expiration_time
  }
  token = jwt.encode(payload,secret_key,algorithm="HS256")
  print("token",token)
  return token

async def verify_token(token:str):
  decode_token = jwt.decode(token,secret_key,algorithms=["HS256"])
  
  return decode_token['email'] , decode_token['user_id']

@app.post('/login')
async def login_user(email:str,password:str,response: Response):
  user = collection.find_one({"email":email})
  if user is None or user["password"] != await hash_password(password):
        raise HTTPException(status_code=401, detail="인증 실패: 이메일 또는 비밀번호가 올바르지 않습니다.")
  user_id = str(user["_id"])  # 사용자 ID를 문자열로 변환
  access_token = await generateJWT(email, user_id)
  #쿠키에 access_token을 담는 로직 key, value 값으로 설정
  response.set_cookie(key="access_token", value=access_token)
  return {"message": "로그인 성공"}

  #쿠키에 담겨있는 토큰 가져와 검증
  @app.get("/protected")
async def protected_route(access_token: str = Cookie(None)):
    if access_token is None:
        raise HTTPException(status_code=401, detail="인증 실패: 액세스 토큰이 없습니다.")
    email , user_id = await verify_token(access_token)
    
    return {"email": email , "user_id": user_id}

해결 내용 : jwt의 내장함수들의 사용법을 검색해 디코딩과 같은 필요한 작업에 활용함

알게된 점 : 파이썬의 문법들에 대해서 학습하는 중에 raise와 같은 문법에 사용법에 대해서 알게됨

헷갈리거나 실수한 점 :

token = jwt.encode(payload,secret_key,algorithm="HS256")

decode_token = jwt.decode(token,secret_key,algorithms=["HS256"])

# jwt에서 token을 encode할 때에는 algorithm="HS256" 사용하는데
# decode시에는 algorithms=["HS256"] 사용하는것에 에러를 내보냄

#  File "/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/site-
# packages/jwt/api_jwt.py", line 147, in decode_complete
#    raise DecodeError(
# jwt.exceptions.DecodeError: It is required that you pass in a value for the "algorithms"
# argument when calling decode().

회고 : 2주 4일차를 진행하면서 라이브러리를 다양하게 활용할 수 있는 방법이 있다는 것을 알게되고 실습을 진행하면서 에러를 만들어내고 처리하는것에 익숙해지고 있다.

profile
🤦‍♂️

0개의 댓글