[DRF] JWT Authentication

송민준·2023년 3월 17일
0

출그니 (캡스톤)

목록 보기
2/6

API는 클라이언트가 올바른 클라이언트인지 확인하기 위해 인증 절차를 거치고 API를 이용하도록 한다.

django 프로젝트를 시작하고 나면 기본적으로 Basic 인증 방식을 거치게 된다. 하지만 이 방식은 보안에 매우 취약해 개발 목적으로만 사용한다.

다른 인증 방식으로는 Session, Token 인증 방식이 있다.

두 인증 방식의 공통점은 처음 아이디와 패스워드를 통해 인정 요청을 보냈을 때 서버에게 받은 Token을 세션 또는 쿠키(브라우저)에 저장한다는 점이다.

이 토큰을 헤더에 포함하고 다른 API 요청을 보내면 서버는 Token이 등록됨을 확인한 후 데이터를 제공한다.

만약 토큰을 포함하지 않는다면 다음과 같은 에러를 보게 된다.

이 두 방식의 단점은 쿠키나 세션 IP가 탈취 당하면 손을 못쓴다.

JWT 인증 방식은 이 둘과 다르게 서버에 따로 Token을 보관하지 않는다. 서버로 부터 생성된 JWT Token은 유저만 보관하고 JWT 해독 방식에 의해 인증이 된다.

JWT는 header, payload, signiture로 구성되어 있다.

JWT 유효성 검사는 header + payload + 서버 key 로 만들어진 signiture의 비교로 이루어진다. 3가지가 일치하면 서버는 정상적으로 API를 제공한다.

게다가 시간이 지나면 access jwt가 파기되며 refresh jwt를 이용해서 재생성해야한다.

이 JWT를 통해 인증을 하는 방식이 JWT Authentication이다.

settings.py


from datetime import timedelta
REST_FRAMEWORK = {
		# 기본적인 인증 방식은 JWTAuthentication으로 한다.
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework_simplejwt.authentication.JWTAuthentication',
    ],
		# 기본적인 권한은 인증이 되면 제공하는 식으로 한다.
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.IsAuthenticated',
    ]
}
# JWT 설정
SIMPLE_JWT = {
    'ACCESS_TOKEN_LIFETIME': timedelta(minutes=30),
    'REFRESH_TOKEN_LIFETIME': timedelta(days=7),
    '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(days=50),
    'SLIDING_TOKEN_REFRESH_LIFETIME': timedelta(days=100),
}

urls.py

루트 url

urlpatterns = [
    ...
    # 차례대로 token 생성, 재생성, 확인
    path('api/token/', TokenObtainPairView.as_view(), name='token_refresh'),
    path('api/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
    path('api/token/verify/', TokenVerifyView.as_view(), name='token_verify')

]

views.py

이 프로젝트를 하면서 가장 의아했던 점이 있다.

모든 API는 token을 이용한다. 그래서 api/token/ 에서 아이디와 패스워드를 이용하여 jwt 토큰을 부여 받는다.

의문인건 그럼 그 전에 회원가입을 해야하는데 token이 필요하다는 것이었다. (철학자의 원탁?)

찾아보니 view 마다 권한을 따로 설정할 수 있으며 default 권한은 setting에서 설정하는 것임을 알게 되었다.

다음과 같이 회원가입에 따로 권한을 설정했다.

class UserSignupView(APIView):
    permission_classes = [AllowAny]
    queryset = User.objects.all()
    serializer_class = UserSerializer
    def post(self, request):
        serializer = UserSerializer(data=request.data)
        data = {}
        if serializer.is_valid():
            user = serializer.save()
            data['user_nickname'] = serializer.data['user_nickname']
        else:
            data = serializer.errors
            return Response(data, status=status.HTTP_400_BAD_REQUEST)
        return Response(data)

회원가입할 때 JWT를 발행할 수 있지만 회원가입 후 로그인하는 것으로 만들기 위해 따로 토큰 발행을 하지 않았다.

profile
개발자

0개의 댓글