이 글은 길어질 예정이다.
로그인 그리고 js와의 통신은 결코 쉽지 않았다.
수많은, 정말 수많은 오류를 만났지만 오류를 해결하는 데 급급해 기록을 남기지 못해 아쉬울 따름이다.
다만 해결된 지금 나와 똑같은 오류를 마주했을 사람들에게 해결법을 남기고자 한다.
먼저 통신의 과정을 설명한다. 통신은 다양한 용도로 사용했지만 그 중 한가지만 예시로 첨부하는 바이다.
axios
.post("http://localhost:8000/make_prompt/", data)
.then((response) => {
console.log(response);
navigate("../result"); // POST 요청 완료 후에 navigate 호출
})
.catch((error) => {
console.log(error);
});
js(front)파일에서 axios통신을 요청한다. axios통신은 js를 위한 Promise API를 활용하는 HTTP 비동기 통신 라이브러리이다. 쉽게 말하면 js에서 서버와 통신하고자 할 때 사용되는 라이브러리이며 http프로토콜을 사용하는 것이다.
axios통신을 위해서는 설치도 필요하다.
import axios from "axios";
axios 통신을 통해 request를 요청하고자 하는 back-end의 링크를 작성해 준다. 이 프로젝트의 경우 포트 8000번이 back-end의 주소이며 /make_prompt/는 우리가 생성한 url이다.
💡 포트 번호에 유의해야 한다. 여기서도 js파일이 실행되는 포트는 3000번이나 요청 주소가 8000번 포트이므로 주소에 8000포트를 적어주어야 한다. 내 주소가 아닌 요청 주소를 적는다는 것을 헷갈리지 말자.
GET방식은 보안에 취약하고 우리는 추후 이 서비스 배포 예정에 있기 때문에 POST방식으로 요청하였으며,전달하고자 하는 데이터를 url링크 옆에 적어준다.
(데이터는 model로 정의해 두면 좋다.)
✨모든 통신에서 예외 처리는 필수이다.
js에서의 처리(요청)이 끝났다면 이제 응답하는 부분을 구현할 차례이다.
def post(self, request, *args, **kwargs):
place = request.data.get('place')
companions = request.data.get('companions')
nights = request.data.get('nights')
theme = request.data.get('theme')
# 여기서 가져온 데이터로 하고 싶은 작업을 진행합니다.
#(예시)
#userPlan = Userplan(place=place, companions=companions, nights=nights, theme=theme)
#userPlan.save()
return Response()
js와의 통신을 통해 front에서 받아온 변수를 사용하고 싶은 class내부에 post함수를 구현하였다. 인자는 순서대로 그 class의 인스턴스, 요청 객체, 반응형(개수가 정해지지 않은)인자, 넘기는 인자 키워드 튜플 인데 알아두면 좋다.
함수 내부에서는 드디어 전달된 데이터 중 특정 필드를 지정해 그 값을 가져온다.
변수명 = request.data.get('필드명')
그리고 나면 받아온 데이터를 마음껏 사용하고,
return response()로 응답을 돌려주면 끝이 난다.
로그인도 id와 password를 전달하는 것은 같은 통신 방식으로 할 수 있다. 그러나 나는 사용자를 비교하지 못하는 오류에 봉착했다.
결과적으로는 jwt인증을 하지 않아서 발생한 문제였다.
추가적으로 jwt인증 방법을 소개하겠다.
먼저 jwt를 설치한다.
pip install djangorestframework djangorestframework-jwt
다음으로는 settings.py에 가서 REST_FRAMEWORK부분에 아래와 같이 추가한다.
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.BasicAuthentication',
'rest_framework.authentication.SessionAuthentication',
'rest_framework_jwt.authentication.JSONWebTokenAuthentication'
]
이것도 추가한다.
JWT_AUTH = {
'JWT_ALLOW_REFRESH' : True
'JWT_SECRET_KEY' : SECRET_KEY,
'JWT_ALGORITHM' : 'HS256',
'JWT_EXPIRATION_DELTA' : datetime.timedelta(days=1),
'JWT_REFRESH_EXPIRATION_DELTA': datetime.timedelta(days=7)
}
jwt토큰은 유효 기간이 정해져 있어 자동으로 갱신 받기 위해 allow_refresh를 true로 설정한다. 해시(암호화)알고리즘은 HS256을 사용했다. JWT_EXPIRATION_DELTA는 토큰을 갱신할 수 있는 기간을 의미한다. 즉, 로그인이 유지되는 시간이다.
➕secret key는 django의 보안 요소로서 분리한 후 settings파일에서 다시 받아오는 것이 좋다.
def get_secret(setting, secrets=secrets):
"""비밀 변수를 가져오거나 명시적 예외를 반환한다."""
try:
return secrets[setting]
except KeyError:
error_msg = "Set the {} environment variable".format(setting)
raise ImproperlyConfigured(error_msg)
SECRET_KEY = get_secret("SECRET_KEY")
이제 urls.py에서도 아래 링크를 추가한다.
path('api/token/', obtain_jwt_token)
path('api/token/refresh/', refresh_jwt_token),
path('api/token/verify/', verify_jwt_token),
마지막으로..........
views.py파일에
from rest_framework.decorators import api_view, permission_classes, authentication_classes
from rest_framework.permissions import IsAuthenticated
from rest_framework_jwt.authentication import JSONWebTokenAuthentication
를 추가하고, 로그인 데이터(id,pwd)를 통신하는 함수 앞에 아래 코드를 한번 더 추가한다.
@api_view(['GET'])
@permission_classes((IsAuthenticated, ))
@authentication_classes((JSONWebTokenAuthentication,))
이로서 jwt토큰 인증 방식은 끝이다.
엄청 길고 복잡하며, 추가로 설정할 수 있는 것들도 많지만 최소한만을 설명했다.
통신은 axios방식만 존재하지는 않는다. 유명한 통신 방식으로는 json도 있다. 그러나 나는 가장 쉬운 방식을 택했으며, 상황에 맞게 사용하면 된다.
통신 방식을 소개했지만 실제로 이 통신을 시도하다 보면 이론과는 다른 오류들을 다양하게 만날 수 있다.(jwt는 더더더 그렇다.) settings에 포함되어야 할 내용이 빠질 수도 있고, 그냥 네트워크 오류일 수도 있고, 서버가 꺼져 있는 상태에서 재시도해 오류 없이도 실행되지 않을 수 있다.
당황하지 말고 이런 가능성들을 순서대로 체크해 오류를 해결해 나가면 문제는 해결되고, 첫 통신에 성공하면 그 뒤로는 통신을 자유롭게 사용할 수 있다.💦