Django DRF 라이브러리를 사용하여 JWT 회원가입, 로그인 기능을 구현해보았다.
먼저 SimpleJWT docs를 통해 기본 환경설정을 해주었다.
https://django-rest-framework-simplejwt.readthedocs.io/en/latest/getting_started.html
기본 환경설정을 끝낸 후
회원 model은 장고에서 기본적으로 제공하는 User model을 사용했다. 왜냐하면 회원가입 시 필요한 정보를 ID, PASSWORD, e-mail이면 충분하다고 생각했다. 추후 필요한 정보는 프로필 테이블을 따로 생성하여 저장할 생각이다.
기본 User 모델 필드 중 사용할 필드는 username, email, password 세가지 이다. (username을 ID로 활용)
다음 회원가입 Serializer를 구현한다.
from django.contrib.auth.models import User
from django.contrib.auth.password_validation import validate_password
from rest_framework import serializers
from rest_framework.validators import UniqueValidator
class RegisterSerializer(serializers.ModelSerializer):
email = serializers.EmailField(
required=True,
validators=[UniqueValidator(queryset=User.objects.all())],
)
password = serializers.CharField(
write_only=True,
required=True,
validators=[validate_password],
)
password2 = serializers.CharField(write_only=True, required=True)
class Meta:
model = User
fields = ('username', 'password', 'password2', 'email')
def validate(self, data):
if data['password'] != data['password2']:
raise serializers.ValidationError(
{"password": "Password fields didn't match."})
return data
def create(self, validated_data):
user = User.objects.create_user(
username=validated_data['username'],
email=validated_data['email'],
)
user.set_password(validated_data['password'])
user.save()
return user
시리얼라이저에서 비밀번호가 일치하는지 검증하는 과정을 함수로 구현했고 검증이 완료되면 생성하도록 함수로 구현했다.
다음으로 views 파일에 APIView를 구현했다.
from rest_framework.views import APIView
from .serializers import RegisterSerializer
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
from rest_framework import status
from rest_framework.response import Response
class RegisterAPIView(APIView):
def post(self, request):
serializer = RegisterSerializer(data=request.data)
if serializer.is_valid():
user = serializer.save()
token = TokenObtainPairSerializer.get_token(user)
refresh_token = str(token)
access_token = str(token.access_token)
res = Response(
{
"user": serializer.data,
"message": "register success",
"token": {
"access": access_token,
"refresh": refresh_token,
},
},
status=status.HTTP_200_OK,
)
res.set_cookie("access", access_token, httponly=True)
res.set_cookie("refresh", refresh_token, httponly=True)
return res
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
POST 방식으로 요청이 들어오면 데이터를 토큰에 담고 access 토큰과 refresh 토큰을 생성하여 쿠키에 담아주었다.
다음으로 urls 설정해준다.
# users/urls.py
from django.urls import path
from .views import RegisterAPIView
urlpatterns = [
path('register/', RegisterAPIView.as_view()),
]
# base/urls.py
from django.contrib import admin
from django.urls import path, include
from rest_framework_simplejwt.views import (
TokenObtainPairView,
TokenRefreshView,
)
urlpatterns = [
path('admin/', admin.site.urls),
path('api/token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
path('api/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
path('api/users/', include('users.urls')),
]
마이그레이션을 진행하고 api 테스트를 해보겠다. / Insomnia를 사용하여 테스트를 진행하였다.
회원가입이 정상적으로 이루어지며 access토큰과 refresh토큰을 생성한 것을 확인할 수 있다.
다음으로 로그인 API를 구현해보았다.
먼저 시리얼라이저를 구현하자.
class LoginSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('username', 'password', 'email')
ModelSerializer를 이용하여 User 모델에서 세가지 필드를 받아왔다.
다음 views파일에서 API를 구현하자.
from rest_framework.views import APIView
from .serializers import RegisterSerializer, LoginSerializer
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
from rest_framework import status
from rest_framework.response import Response
from django.contrib.auth import authenticate
class LoginAPIView(APIView):
def post(self, request):
user = authenticate(
username = request.data.get("username"),
password = request.data.get("password"),
)
if user is not None:
serializer = LoginSerializer(user)
token = TokenObtainPairSerializer.get_token(user)
refresh_token = str(token)
access_token = str(token.access_token)
res = Response(
{
"user": serializer.data,
"message": "Login success",
"token": {
"access": access_token,
"refresh": refresh_token,
},
},
status=status.HTTP_200_OK,
)
return res
else:
return Response(status=status.HTTP_400_BAD_REQUEST)
POST방식으로 요청이 들어오면 username과 password를 확인하고 토큰을 확인한다.
url을 설정하고 구현이 잘됬는지 확인해보자.
urlpatterns = [
path('register/', RegisterAPIView.as_view()),
path('login/', LoginAPIView.as_view()),
]
로그인이 잘 되는것을 확인할 수 있다.
다음으로 로그아웃 API를 구현해보자
로그아웃은 시리얼라이저를 따로 구현할 필요가 없고 POST 방식으로 요청이 들어오면 쿠키에서 토큰을 제거해주면 로그아웃이 되도록 구현해보았다.
# users/views.py
class LogoutAPIView(APIView):
def post(self, request):
response = Response({
"message": "Logout success"
})
response.delete_cookie("access")
return response
로그아웃도 잘 되는것을 확인할 수 있다.
댓글