[JWT] 인증과 인가 그리고 JWT에 대해 알아보기
인증(authentication): 로그인, 아이디와 패스워드를 통해 회원임을 인증 받는 것
인가(autherization): 회원으로만 할 수 있는 행동을 할 때 서버가 회원임을 확인하고 행동을 인가하는 것
인가를 위해 매 요청마다 아이디와 비밀번호가 담겨서 날아다니면 보안상 위험하며 매번 비밀번호가 알고리즘으로 암호화된 계산값과 일치하는지 확인하는 작업을 거쳐야 해서 시간과 자원을 많이 사용하게 된다.
해결책
메모리를 사용한 세션/쿠키 방식
- 장점
- 메모리를 사용하면 비교적 빠르다
- 단점
- 용량이 작기 때문에 사용자가 동시에 많이 접속하면 메모리가 부족해짐
- 서버가 꺼져버리면 데이터가 휘발 → 모든 사용자 로그인 튕김
서버를 사용한 세션/쿠키 방식
- 장점
- 용량이 크기 때문에 동시접속자가 많을 때 메모리 방식보다 안정적
- 단점
- 메모리 방식보다 느리다
- 서버를 여러 대 둘 경우, 요청을 분산하는 로드밸런싱을 하는데 인증을 받은 서버와 이후 인가가 필요한 요청을 받은 서버가 다를 경우 세션 유지가 되지 않는다.
- 보완방법
- 인증 정보를 특정 데이터베이스용 서버에만 넣어 두는 방법(하지만 속도가 많이 느리다)
- Redis, MemCached와 같은 메모리형 데이터베이스 서버를 사용한다.(메모리 방식보다 안정적이지만 역시 과부하 발생 가능성 존재)
JWT(Json Web Token)
특징
- 사용자가 로그인을 하면 토큰을 전달해주며, 서버에는 그 정보를 따로 저장하지 않음(세션/쿠키 방식과 달리 stateless함)
- 인코딩된 3가지 데이터를 이어 붙임(xxxx.yyyyy.zzzzz~)
- 이 3가지는 각각 1. 헤더 2. 페이로드 3. 서명으로 구분됨
- 2번 페이로드를 디코딩하면 json 형식으로 여러 정보들이 들어있음
- 이 안에는 토큰을 누가 누구에게 발급했는지, 언제까지 유효한지, 서비스가 사용자에게 이 토큰을 통해 공개하기 원하는 내용을 담을 수 있음(클레임)
- 1번 헤더 부분은 type 즉 토큰의 타입인 JWT가 들어가 있음(고정값)
- 다음으로는 alg(알고리즘), 즉 3번 서명값을 만드는데 사용되는 알고리즘이 지정되며 이 알고리즘으로 만든 값은 복호화가 불가능(HS256 등)
- 1번 헤더와 2번 페이로드 그리고 ‘서버에 감춰놓은 비밀값’ 총 3가지를 암호화 알고리즘에 넣고 돌리면 3번 서명값이 나오게 된다.
인가 과정
- 서버는 요청이 들어오면 token의 1, 2번 값을 서버의 비밀키와 함께 돌려 3번 서명값과 일치하는지 확인한다. 일치한다면 토큰 만료기간까지 확인 후에 인가를 하게됨
단점
- stateful한 세션/쿠키 방식은 기억하는 대상의 상태를 언제든 제어가 가능하다. 예를들어 한 기기에서만 로그인이 가능하도록 한다면 새로운 기기에서 로그인 시 이전 로그인 세션 종료가 가능하다.
- 하지만 JWT는 이러한 컨트롤이 불가능하다. 만약 토큰이 탈취당하면 토큰 만료 전까지 토큰 무효화 할 수 없다.
Refresh Token
- 위 단점을 보완하기 위한 방법으로 로그인 후 access(짧은 수명), refresh(긴 수명) 2개의 토큰을 준다.
- 이때 refresh 토큰은 DB에도 저장하게 된다.(stateful)
- 유저는 access 토큰이 만료되면 refresh 토큰을 서버에 보내고 refresh 토큰 대조/토큰이 만료되지 않았으면 서버는 새로운 acceess 토큰을 유저에거 발급한다.
- refresh 토큰을 사용할 경우 해킹이 감지되거나 했을 때(수상한 아이피, 사용자의 신고 등) 서버가 어떤 조치를 취할(refresh 토큰을 강제 만료) 수 있음
Django로 JWT 확인하기
-
django에서 JWT access token을 발급받아 이를 JWT 공식 사이트에서 decode 해보았다.
- 먼저 header에는 token type과 alg가 들어있는 것을 확인할 수 있다.
- 다음 payload에는 클레임들을 확인할 수 있다.
- exp: 토큰 만료 시간
- iat: 토큰 발급 시간
- jti: 중복 방지를 위한 JWT 고유 식별자
- jti 이후 클레임들은 서버에서 직접 토큰에 담은 유저 정보와 관련된 클레임들이다.
#serializers.py from rest_framework_simplejwt.serializers import TokenObtainPairSerializer class SellerTokenObtainPairSerializer(TokenObtainPairSerializer): @classmethod def get_token(cls, user): if user.is_staff == True: token = super().get_token(user) token['username'] = user.username token['email'] = user.email token['is_staff'] = user.is_staff return token
-
django에서 위 코드를 통해 유저에게 JWT 토큰을 반환할 때 username, email, is_staff 정보가 추가로 payload에 담기게 되며 이외의 정보들을 추가할 수 있다.
-
마지막 서명에서는 헤더, 페이로드, 비밀키를 암호화 했음을 알 수 있다.
다음은 django에서 JWT 관한 설정들이다.
#settings.py
'''
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAuthenticated',
),
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework_simplejwt.authentication.JWTAuthentication',
'rest_framework.authentication.BasicAuthentication',
'rest_framework.authentication.SessionAuthentication',
),
}
'''
SIMPLE_JWT = {
'ACCESS_TOKEN_LIFETIME': timedelta(minutes=30),
'REFRESH_TOKEN_LIFETIME': timedelta(days=14),
'ROTATE_REFRESH_TOKENS': True,
'BLACKLIST_AFTER_ROTATION': True,
'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),
}
-
먼저 Django REST Framework에서 인가를 위해 JWT를 사용했기 때문에 REST Framework의
DEFAULT_AUTHENTICATION_CLASSES
에rest_framework_simplejwt.authentication.JWTAuthentication
를 추가해주었다. -
다음으로 simple JWT 설정을 확인해보면,
access token의 만료시간은 30분, refresh token의 만료기간은 2주로 설정된 것을 확인할 수 있다. -
또한 암호화 알고리즘은 'HS256'이며, 서명을 만드는데 사용된 비밀키는 django의
SECRET_KEY
와 동일하게 설정해주었다.
Author And Source
이 문제에 관하여([JWT] 인증과 인가 그리고 JWT에 대해 알아보기), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@dhleeone/JWT인증과-인가-그리고-JWT에-대해-알아보기저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)