11월 04일 원티드 프리온보딩 백엔드 10일차 TIL

django Field 종류 정리

:one: 진행상황

  • User 모델 및 API 설계

:two: 진행상황리뷰

# views.py
...
from rest_framework_simplejwt.tokens import RefreshToken
...
class LoginView(APIView):
    def post(self, request: Request) -> Response:
...
        token: Final[RefreshToken] = RefreshToken.for_user(user)
        refresh: Final[RefreshToken] = str(token)
        access: Final = str(token.access_token)
        response = Response({"user": user.id})
        response.set_cookie(key="refresh", value=refresh, httponly=True)
        response.set_cookie(key="access", value=access, httponly=True)
        return response

class LogoutView(APIView):
    authentication_classes = [JWTAuthentication]
    permission_classes = [IsAuthenticated]

    def post(self, request: Request) -> Response:
        ...
        # get token from request cookie
        refresh: Final = request.data.get("refresh")
        ...
        try:
            # delete token from database
            token: Final = RefreshToken(refresh)
            token.blacklist()
        except Exception:
            raise ParseError("Refresh token is invalid.")
        # delete token from cookie
        response = Response({"status": True})
        response.delete_cookie("refresh")
        response.delete_cookie("access")
        return response

# tests.py
class TestUserView(APITestCase):
    ...
    def test_logout(self):
    ...
        # get tokens
        refresh = logged_response.cookies["refresh"].value
        access = logged_response.cookies["access"].value
        # request logout with tokens
        response: Final[Response] = self.client.post(
            "/api/v1/users/logout/",
            {"refresh": refresh},
            HTTP_AUTHORIZATION=f"Bearer {access}",
        )
  • JWT 생성해 쿠키에 등록하여 로그인 인증하는 코드 작성.

:three: Today I Learned

JWT

  • JSON Web Token
  • 웹 상에서 로그인 인증을 위한 토큰을 JSON 형식으로 표현한 것
  • 헤더(형식 및 알고리즘), 페이로드(내용), 서명(헤더와 페이로드를 합쳐 암호화한 것, 인증시 필요)으로 구성

djangorestframework-simplejwt

  • DjangoDRF 사용 시 JWT를 쉽게 사용할 수 있도록 도와주는 라이브러리
  • 설치: pip install djangorestframework-simplejwt
  • 설정
    # config/settings.py
    INSTALLED_APPS = [
        ...
        "rest_framework_simplejwt",
        'rest_framework_simplejwt.token_blacklist', # 보안을 위해 블랙리스트 사용
        ...
    ]
    ...
    EST_FRAMEWORK = {
      'DEFAULT_AUTHENTICATION_CLASSES': (
          'rest_framework_simplejwt.authentication.JWTAuthentication',
      ),
    }
    
    REST_USE_JWT = True
    
    SIMPLE_JWT = {
        'ACCESS_TOKEN_LIFETIME': timedelta(hours=2),
        'REFRESH_TOKEN_LIFETIME': timedelta(days=7),
        'ROTATE_REFRESH_TOKENS': False,
        'BLACKLIST_AFTER_ROTATION': True,
        'TOKEN_USER_CLASS': 'user.User',
    }
    
  • 사용
    # views.py
    from rest_framework_simplejwt.tokens import RefreshToken
    
    # JWT 발급 View(로그인 등)
    class CreateJwtView(APIView):
        def post(self, request: Request) -> Response:
            ...
            # 유저로부터 refresh 토큰을 생성
            token: Final[RefreshToken] = RefreshToken.for_user(user)
            # refresh 토큰을 문자열로 변환
            refresh: Final[RefreshToken] = str(token)
            # refresh 토큰에서 access 토큰을 생성해 문자열로 변환
            access: Final = str(token.access_token)
            # 응답 생성
            response = Response({"data": data})
            # 토큰을 쿠키에 등록
            response.set_cookie(key="refresh", value=refresh, httponly=True)
            response.set_cookie(key="access", value=access, httponly=True)
            ...
            # 응답 반환
            return response
    
    # JWT 인증이 필요한 View
    class CheckAuteView(APIView):
        # 인증 시 JWTAuthentication 사용
        authentication_classes = [JWTAuthentication]
        permission_classes = [IsAuthenticated]
    
    # JWT 만료 View(로그아웃 등)
     class ExpireJwtView(APIView):
        ...
        def post(self, request: Request) -> Response:
            ...
            # 응답에서 refresh 토큰을 가져옴
            refresh: Final = request.data.get("refresh")
            ...
            # refresh 토큰을 RefreshToken 객체로 변환
            token: Final = RefreshToken(refresh)
            # 블랙리스트에 등록
            token.blacklist()
            # 응답 생성
            response = Response({"status": True})
            # 쿠키에서 토큰 삭제
            response.delete_cookie("refresh")
            response.delete_cookie("access")
            # 응답 반환
            return response
    
  • 테스트 시
    • 실 사용시에는 아마 대부분 브라우저에서 처리해줄 듯
      # tests.py
      class APITestView(APITestCase):
        # JWT 인증 필요한 View 테스트
        ...
        def test_get_token(self):
            # JWT 발급 View 호출
            response = self.client.post(
                # JWT 발급 URL,
                # JWT 발급 데이터,
            )
            # 응답 쿠키에서 토큰 추출
            self.refresh = logged_response.cookies["refresh"].value
            self.access = logged_response.cookies["access"].value
            
        def test_check_token(self):
            response: Final[Response] = self.client.post(
                # JWT 인증이 필요한 URL,
                # JWT 인증이 필요한 데이터,
                HTTP_AUTHORIZATION=f"Bearer {self.access}",
            )
            # HTTP 인증 헤더에 access 토큰을 넣어서 요청
      

© 2021. All rights reserved.

Powered by Hydejack v7.5.2