본문 바로가기

멋사 10기 졸업 프로젝트/정리

[django] simple-jwt방식을 이용한 login, logout 기능 구현

drf세션을 통해 회원가입과 로그인은 어떻게 구현하는지 알지만 로그아웃은 모른다.

처음에는 DELETE 메소드로 구현한다고 생각했는데, 데이터는 없애면 큰일이다. 이건 유저 정보를 삭제할 때나 쓰는 거고...서치해본 결과 token을 이용한 방식을 택하기로 했다.

 

처음에는 payjwt였나.. 그 방식으로 하려 했는데 자꾸 권한이 없다고 나와서 simple jwt방식으로 다시 해봤다.

 


 

Token

세션(쿠키)를 이용한 방식은 수업시간에 flask를 다루면서 간단하게 배웠다. 쿠키까지는 안썼지만...

정리해보면 이렇다.

 

1. 쿠키(cookie)

  • 클라이언트(브라우저, 사용자)에서 관리한다.
  • 서버와 클라이언트가 연결되면 자동으로 생성되고, 유저가 데이터를 요청하면 응답할 때 쿠키에 담아서 정보를 보낸다.
  • 이름, 값, 만료날짜, 경로정보로 구성
  • 보안이 약함

2. 세션(session)

  • 서버에서 관리한다. -> 서버 부담 증가
  • 유저 접속 시 생성되는 세션 ID를 사용하고, 세션 스토리지에 정보를 저장한다.
  • 세션 ID를 쿠키를 통해 기억, 즉 세션 정보를 쿠키에 저장할 수 있다.

사실 세션이랑 쿠키는 같이 보는 게 맞는 것 같다.

 

3. 토큰(token)

  • 유저 인증을 위한 암호화된 문자열
  • 인증 성공 시 서버는 토큰을 생성 해 클라이언트에 문자열을 보낸다.
  • JWT(Json Web Token)은 인증에 필요한 정보들을 암호화한 토큰으로, 이 방식을 사용하면 별도의 저장소 관리가 필요없다.
  • RefreshToken이라고 해서 보안을 위해 유효기간이 있는 토큰 발행이 따로 있다. -> 난이도 상승

 


 

LOGIN,LOGOUT구현

 

#settings.py

from datetime import timedelta

SIMPLE_JWT = {
    'ACCESS_TOKEN_LIFETIME': timedelta(minutes=5),
    'REFRESH_TOKEN_LIFETIME': timedelta(days=1),
    'ROTATE_REFRESH_TOKENS': False,
    'BLACKLIST_AFTER_ROTATION': False,
    'UPDATE_LAST_LOGIN': False,

    'ALGORITHM': 'HS256',
    'SIGNING_KEY': SECRET_KEY,
    'VERIFYING_KEY': None,
    'AUDIENCE': None,
    'ISSUER': None,
    'JWK_URL': None,
    'LEEWAY': 0,

    'AUTH_HEADER_TYPES': ('Bearer',),
    'AUTH_HEADER_NAME': 'HTTP_AUTHORIZATION',
    'USER_ID_FIELD': 'id',
    'USER_ID_CLAIM': 'user_id',
    'USER_AUTHENTICATION_RULE': 'rest_framework_simplejwt.authentication.default_user_authentication_rule',

    'AUTH_TOKEN_CLASSES': ('rest_framework_simplejwt.tokens.AccessToken',),
    'TOKEN_TYPE_CLAIM': 'token_type',
    'TOKEN_USER_CLASS': 'rest_framework_simplejwt.models.TokenUser',

    'JTI_CLAIM': 'jti',

    'SLIDING_TOKEN_REFRESH_EXP_CLAIM': 'refresh_exp',
    'SLIDING_TOKEN_LIFETIME': timedelta(minutes=5),
    'SLIDING_TOKEN_REFRESH_LIFETIME': timedelta(days=1),
}

simplejwt사용을 위해 pip install djangorestframework-simplejwt 필수

여기서 토큰과 관련된 여러 설정을 하는데, 특히 주목 할 건 토큰의 유효 기간을 설정하는 위의 두 줄.

 

 

 

 

#models.py

class User(AbstractUser):
    nickname=models.TextField(max_length=50)
    create_time=models.DateTimeField(auto_now_add=True)
    delete_time=models.DateTimeField(auto_now=True)

사용된 유저모델이다.  time은 자동 생성이고...django의 기본 모델을 사용해서 내가 로그인할 때 입력한 데이터는 nickname만 있음.

 

 

 

 

#serializers.py

class UserLoginSerializer(serializers.Serializer):
    username=serializers.CharField(max_length=64)
    password=serializers.CharField(max_length=64, write_only=True)

    def validate(self, data):
        username=data.get("username", None)
        password=data.get("password", None)


        if User.objects.filter(username=username).exists():
            user=User.objects.get(username=username)

            if not user.check_password(password):
                raise serializers.ValidationError()
        else:
            raise serializers.ValidationError("User does not exist")
        token = RefreshToken.for_user(user=user)
        data = {
            'id': user.id,
            'nickname' : user.nickname,
            'refresh_token' : str(token),
            'access_token' : str(token.access_token)
        }
        return data

 

위에서 username(아이디)가 존재하는지, 비밀번호가 맞는지 체크한 후, 조건에 부합하면 토큰을 발행한다.

토큰을 발행하면 문자열로 치환한 뒤 유저 아이와 닉네임과 함께 data로 반환한다.

 

실행 예시

 

 

 

#views.py

#로그인 함수
class LoginView(views.APIView):
    serializer_class = UserLoginSerializer

    def post(self, request):
        serializer = self.serializer_class(data=request.data)
        serializer.is_valid(raise_exception = True)
        token = serializer.validated_data
        return Response({"token":token}, status=HTTP_200_OK)

#로그아웃 함수
class LogoutView(views.APIView):

    def post(self, request):
        response = Response({
            "message": "Logout success"
            }, status=HTTP_202_ACCEPTED)
        response.delete_cookie('refreshtoken')

        return response

둘다  post방식으로, 특히 로그아웃 함수는 delete_cookie로 토큰을 삭제 함.

 


 

 

 

벡엔드만 담당하다보니 알맞게 로그아웃 됐는지 모르겠다.

특히 drf를 사용하다보면 내가 맞게 하고 있는지...토큰 방식을 이번 프로젝트에서 활용할지도 모르겠다. 로그아웃 기능을 없앨 수도?

늘 유저 부분이 어려웠는데...아직도 어렵다 아마 가능하면 유저 프로필을 따로 나누어서 구현할지도. 가능하면 기록할 듯.

 

 

 

 


참고사이트

https://velog.io/@auddwd19/DRF-simple-JWT-%EB%A1%9C%EA%B7%B8%EC%9D%B8%EA%B5%AC%ED%98%84

 

DRF- simple JWT 로그인구현

저번 회원가입에 이어서 로그인 부분을 진행generics.genericsAPIView에 해당하는 로그인 창이 나온다 여기에 로그인을 진행한다면HTML form처럼 비밀번호는 암호화 되서 들어온다.로그인이 완료된다면

velog.io

https://hyeo-noo.tistory.com/302

 

[Django] DRF를 사용한 JWT Authentication #2

이번 포스팅에서는 JWT를 생성하고 로그인,로그아웃 기능을 구현하는 방법을 정리해 보려고 한다. 로그인 로직 클라이언트는 LoginApi를 호출하면서 {"username": "이름", "password": "비번"} 정보를 전달

hyeo-noo.tistory.com