Token 인증 VS JWT 인증
DRF Token
- 단순한 랜덤 문자열로 각 User와 일대일 매칭
- 유효기간 X
- Token만으로 어떤 유저인지 알 수 없고 Token에 매칭된 User가 누구인지 데이터베이스에서 찾아야만 알 수 있다
JWT ( JSON Web Token )
- 토큰 자체에 User 데이터를 담을 수 있어 데이터베이스를 조회하지 않아도 User 인증이 가능하다
- 포맷 : "헤더.내용.서명" → Header와 payload(내용) : base64인코딩 / signature(서명) : Header와 payload를 조합하고 비밀키로 서명한 후 base64 인코딩
- 서버에서 토큰 발급 시에 비밀키로 서명을 하고 발급 시간 및 유저 정보 등을 저장
- 비밀키로 서명 했기에 위조변조가 불가능 ( 비밀키를 잘 관리하는 것이 중요! )
- 서명은 암호화가 아니기에 누구라도 볼 수 있어 보안성 데이터를 넣지 말고, 최소한의 필요정보만 넣기
- 비밀키 : 장고 기본 settings.SECRET_KEY를 활용 Or 별도로 JWT_SECRET_KEY 설정을 한다
- claim : 담는 정보의 한 부분으로 key:value 형식 -> djangorestframework-jwt에서는 Payload 영역에 usre_id, username, email 라는 claim 사용
- 갱신(Refresh) 매커니즘을 지원 → Token expire time 내에 갱신 Or username/password를 통해 재인증
- 이미 발급된 Token을 폐기(Revoke) 하는 것은 불가능
≫ 스마트폰 앱은 안전한 저장공간이 제공되지만 웹 브라우저에는 없으므로 일반 Token/JWT 토큰 사용시 안전한 장소에 보관하는 것이 중요! + https 통신 활용하기 ( by SSL인증서, Let's Encrypt )
djangorestframework-jwt
설치 : pip install djangorestframework-jwt
# settings.py
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES' : [
...
'rest_framework_jwt.authentication.JWONWebTokenAuthentication',
]
....
}
# urls.py
from rest_framework_jwt.views import obtain_jwt_token, refresh_jwt_token, verify_jwt_token
urlpatterns = [
path('api-jwt-auth/$', obtain_jwt_token), # jwt 획득
path('api-jwt-auth/refresh/', refresh_jwt_token), # jwt refresh
path('api-jwt-auth/verify/', verify_jwt_token), # 현재 client가 가진 토큰이 유효한 token인지 검사
]
HTTPie를 통한 JWT 발급
쉘 > http POST http://주소/api-jwt-auth/ username="유저명" password="암호"
{
"token" : "인증에 성공할 경우, 토큰 응답이 온다. "
}
쉘 > http POST http://주소/api-jwt-auth/verify/ token="토큰"
{
"token" : "검증에 성공할 경우, 토큰 응답이 온다. "
}
발급받은 JWT Token으로 API요청 예시
쉘 > http http://주소/blog/api/post/ "Authorization: JWT 토큰"
c.f ) DRF Token에서는 인증헤더의 시작 문자열로 Token을 썼다 → "Authorization: Token 토큰"
JWT Token 유효기간
유효기간 : settings.JWT_AUTH의 JWT_EXPIRATION_DELTA 에 디폴트 5분 설정
쉘 > http http://주소/blog/api/post/ "Authorization: JWT 토큰"
HTTP/1.0 401 Unauthorized
{
"detail" : "Signature has expired"
}
유효기간이 지난 Token은 위와 같이 "401 Unauthorized" 응답을 받는다
- Token 유효기간 내 : Token만으로 갱신 가능
- Token 유효기간 지남 : username/password를 통해 다시 인증을 받아야만 한다
JWT Token 갱신받기
Token 유효기간 내에만 가능
JWT_ALLOW_REFRESH가 True인 상태에서만 갱신 지원, False인 경우 orig_iat필드를 찾을 수 없다는 오류 뜬다
# settings.py
JWT_AUTH = {
'JWT_ALLOW_REFRESH' : True, #default는 False
}
쉘 > http POST http://주소/api-jwt-auth/refresh/ token="토큰"
{
"token" : "갱신받은 토큰 "
}
djangorestframework-jwt의 주요 settings
# settings.py
JWT_AUTH = {
'JWT_SECRET_KEY' : settings.SECRET_KEY,
'JWT_ALGORITHM' : 'HS256',
'JWT_EXPIRATION_DELTA' : datetime.timedelta(seconds=300),
'JWT_ALLOW_REFRESH' : False,
'JWT_REFRESH_EXPIRATION_DELTA': datetime.timedelta(days=7)
}
- JWT_SECRET_KEY : settings의 SECRET_KEY를 지정할 수도 있지만 jwt의 SECRET_KEY를 별도로 만들어 설정할 수도 있다
- JWT_EXPIRATION_DELTA : 디폴트 5분 / 이 기간 내에 refresh를 요청한다면 Token 만으로 refresh되고, 기간이 지나서 요청한다면 거부되어 username과 password를 통해 새롭게 token을 받아 expire 타임과 refresh타임도 새로 할당받는다
- JWT_REFRESH_EXPIRAION_DELTA : 디폴트 7일