DRF JWT Token #2

Error Coder·2023년 1월 10일
0

로그인 로직

1.클라이언트는 LoginApi를 호출하면서 {"username": "이름", "password": "비번"} 정보를 전달해준다.
2.서버는 username과 password를 가지고, 해당하는 유저를 찾은 다음 jwt_login을 수행한다.
3.jwt_login에서는 access_token과 refresh_token을 생성한다.
4.생성된 access_token은 {"access_token": access_token}형태의 json으로 클라이언트에 전달되고, 생성된 refresh_token은 httpOnly=True 속성을 가진채로 cookie에 삽입된다.

로그아웃 로직

1.클라이언트에서 LogoutApi를 호출한다.
2.호출과 동시에 클라이언트는 가지고 있던 access_token을 삭제한다.
3. 서버에서는 cookie에 존재하는 refreshtoken을 삭제한다.

  • refreshtoken을 삭제함으로써 완전히 로그아웃을 할 수 있다.

access_token 추가 발급

1.클라이언트에서 RefreshJWTtoken을 호출한다.
2.서버는 cookie에 있는 refreshjwttoken을 읽어서 decode한다.
3.decode한 정보로 유저를 추출하고, 로그인 할 때와 마찬가지로 access_token을 새로 만들어서 json 형태로 전달한다.

구현 코드

LoginAPI, LogoutAPI, RefreshJWTToken

## auth/apis.py

import jwt

from rest_framework import status
from rest_framework.views import APIView
from rest_framework.response import Response

from django.contrib.auth import get_user_model
from django.conf import settings
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_protect, ensure_csrf_cookie

from auth.authenticate import generate_access_token, jwt_login
from api.mixins import PublicApiMixin


User = get_user_model()


@method_decorator(ensure_csrf_cookie, name="dispatch")
class LoginApi(PublicApiMixin, APIView):
    def post(self, request, *args, **kwargs):
        """
        username 과 password를 가지고 login 시도
        key값 : username, password
        """
        user = User
        username = request.data.get('username')
        password = request.data.get('password')
        
        if (username is None) or (password is None):
            return Response({
                "message": "username/password required"
            }, status=status.HTTP_400_BAD_REQUEST)
        
        user = User.objects.filter(username=username).first()
        if user is None:
            return Response({
                "message": "유저를 찾을 수 없습니다"
            }, status=status.HTTP_404_NOT_FOUND)
        if not user.check_password(password):
            return Response({
                "message": "wrong password"
            }, status=status.HTTP_400_BAD_REQUEST)
        
        response = Response(status=status.HTTP_200_OK)
        return jwt_login(response, user)
        

@method_decorator(csrf_protect, name='dispatch')
class RefreshJWTtoken(PublicApiMixin, APIView):
    def post(self, request, *args, **kwargs):
        refresh_token = request.COOKIES.get('refreshtoken')
        
        if refresh_token is None:
            return Response({
                "message": "Authentication credentials were not provided."
            }, status=status.HTTP_403_FORBIDDEN)
        
        try:
            payload = jwt.decode(
                refresh_token, settings.REFRESH_TOKEN_SECRET, algorithms=['HS256']
            )
        except:
            return Response({
                "message": "expired refresh token, please login again."
            }, status=status.HTTP_403_FORBIDDEN)
        
        user = User.objects.filter(id=payload['user_id']).first()
        
        if user is None:
            return Response({
                "message": "user not found"
            }, status=status.HTTP_400_BAD_REQUEST)
        if not user.is_active:
            return Response({
                "message": "user is inactive"
            }, status=status.HTTP_400_BAD_REQUEST)
        
        access_token = generate_access_token(user)
        
        return Response(
            {
                'access_token': access_token,
            }
        )
        
        
@method_decorator(csrf_protect, name='dispatch')
class LogoutApi(PublicApiMixin, APIView):
    def post(self, request):
        """
        클라이언트 refreshtoken 쿠키를 삭제함으로 로그아웃처리
        """
        response = Response({
            "message": "Logout success"
            }, status=status.HTTP_202_ACCEPTED)
        response.delete_cookie('refreshtoken')

        return response

generate_access_token, generate_refresh_token, jwt_login

## auth/authenticate.py

import datetime, jwt

from django.conf import settings


def generate_access_token(user):
    access_token_payload = {
        'user_id': user.id,
        'exp': datetime.datetime.utcnow() + datetime.timedelta(
            days=0, minutes=60
        ),
        'iat': datetime.datetime.utcnow(),
    }
    
    access_token = jwt.encode(
        access_token_payload,
        settings.SECRET_KEY, algorithm='HS256'
    ).decode('utf-8')
    
    return access_token
    
    
def generate_refresh_token(user):
    refresh_token_payload = {
        'user_id': user.id,
        'exp': datetime.datetime.utcnow() + datetime.timedelta(days=7),
        'iat': datetime.datetime.utcnow(),
    }
    
    refresh_token = jwt.encode(
        refresh_token_payload,
        settings.REFRESH_TOKEN_SECRET, algorithm='HS256'
    ).decode('utf-8')
    
    return refresh_token


def jwt_login(response, user):
    access_token = generate_access_token(user)
    refresh_token = generate_refresh_token(user)
    
    data = {
        'access_token': access_token,
    }
    
    response.data = data
    response.set_cookie(key="refreshtoken", value=refresh_token, httponly=True)
    
    return response
profile
개발자 지망생

0개의 댓글