나는 Django REST API Framework 를 통해 Login API 를 구축하고
authentication 방법을 Session 방식이 아닌
JWT 방식으로 Access Token 을 검사를 통한 사용자 인증을 구현했다. GitHub 참고
하지만, POST-MAN 을 통해서 HTTP 헤더에 직접 JWT Authorization 을 추가했을 때는 정상적으로
JWT Access Token 을 검사하지만, 브라우저에서 API 요청시에는 헤더에 Authorization 추가가 되지 않아
JWT 인증 실패로 API 가 reject 되고 있었다.
그래서, 해당 이슈를 해결하기 위해서 자동으로 헤더에 포함하는 방법을 구글링해 봤지만
대부분의 게시글이 simple JWT 예제와 POST-MAN 테스트 거나
Fetch API 로 요청 헤더에 Access Token을 직접 추가해서 API 요청을 보내는 방식을 설명하고 있었다.
내가 JWT 를 구현할 때 httponly=True
옵션으로 JavaScript에서는 토큰에 접근할 수 없게 구현해
Fetch API를 통해 헤더에 직접 추가해서 요청을 보낼 수 없을 뿐더러
내가 구현할 방향은 브라우저가 자동으로 헤더에 JWT 를 포함해서 보내고 싶었다.
먼저 로그인 시 발급 받은 JWT Access Token 과 Refresh Token 이 제대로 쿠키에 저장되는지 확인해 보기로 했다.
먼저 내가 구축한 Login API의 views.py
부분이다.
# account/api/views.py
@api_view(['POST'])
@permission_classes([AllowAny])
def LoginAPI(request):
# 사용자 인증
user = authenticate(username= request.data.get("username"), password= request.data.get("password"))
# 등록된 사용자인지 확인
if user is not None:
serializer = UserSerializer(user)
# JWT 토큰
token = TokenObtainPairSerializer.get_token(user)
refresh_token = str(token)
access_token = str(token.access_token)
response = Response(
{
"user": serializer.data,
"message": "login success",
"token": {
"access": access_token,
"refresh": refresh_token,
},
},
status=status.HTTP_200_OK,
)
# JWT 토큰을 브라우저의 쿠키내 저장
response.set_cookie("access_token", access_token, httponly=True)
response.set_cookie("refresh_token", refresh_token, httponly=True)
# 최근 로그인 기록 업데이트
update_last_login(None, user)
return response
else:
return Response(status=status.HTTP_400_BAD_REQUEST)
그리고 간단한 Login 템플릿을 만들고 쿠키 저장소를 확인 해봤다.
쿠키 저장소에는 정상적으로 Access Token과 Refresh Token을 받고 있지만,
Request 헤더에만 제대로 포함되지 않고 있는 것 같다.
쿠키 저장소에 정상적으로 포함된 것을 확인해서
이제 브라우저가 request 전송 시 Access Token 을 포함해서 보내는지 확인 해봤다.
브라우저가 자동으로 Authorization 헤더에 Access Token 을 포함하는게 아니라
Access Token 을 Cookie 에 포함해서 request 를 보내고 있어
DRF 에서 Access Token 을 가져오지 못해 JWT 인증을 정상적으로 하질 못하고 있었던 것이다.
나는 JavaScript 를 사용하지 않고 어떻게 Cookie에 있는 Access Token 을
Authorizaion 으로 옮겨 request를 보낼까 고민하며
다시 Access Token 헤더 관련해서 검색하다가
HTTP request를 view로 이동 시켜주는 middleware 부분에서
Cookie에 저장된 Access Token 을 Authorization 으로 옮겨 뷰로 옮겨주면 된다는 게시글을 발견했다.
따라서, 쿠키에 저장된 JWT 정보를 Authorization 로 옮기는 커스텀 미들웨어를 작성했다.
#middleware/jwt_authentication_middleware.py
from rest_framework_simplejwt.tokens import AccessToken, RefreshToken
class JWTAuthenticationMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
# 쿠키에서 JWT 토큰 데이터를 읽기
access_token_value = request.COOKIES.get('access_token')
if access_token_value:
try:
# JWT 토큰을 디코딩하여 사용자 데이터를 가져옴
access_token = AccessToken(access_token_value)
user = access_token.payload.get('user_id')
# HTTP Authorization 헤더에 JWT ACCESS 헤더 추가
request.META['HTTP_AUTHORIZATION'] = f'Bearer {access_token_value}'
except Exception as e:
# JWT 토큰 디코딩 실패
pass
response = self.get_response(request)
return response
# main/settings.py
# ...
MIDDLEWARE = [
'middleware.jwt_authentication_middleware.JWTAuthenticationMiddleware', # JWT 를 헤더에 포함
# ... 다른 미들웨어 설정
]
미들웨어를 통해, request 헤더를 변경 후 runserver 로 API 확인 결과
정상적으로 JWT 기반으로 사용자 인증을 진행하고 API 권한도 제대로 작동하게 되었다!
https://blog.naver.com/netscout82/222008511406
정말 감사합니다...
잘 봤습니다. 덕분에 고민하던 것을 해결 할 수 있었습니다.
다만, cookie 를 활용한 jwt 관리를 할 경우 브라우저 외에 모바일 어플이나 일반 응용프로그램에서는 적용이 어렵다는 생각이 드는데 혹시 해결이 하신 적 있나요?