스타트 당시 기획했던 서비스는 '사용자의 대답에 따라 다음 동화의 장면을 AI가 자동으로 생성'하는 웹 서비스였다. GPT3를 사용하여 다양한 방법으로 input을 넣고 결과를 받아봐도 올바른 문장 형태조차 만들지 못하여 주제를 바꾸게 되었다.
그렇게 바꾸게 된 주제는 'AI 기반 참여형 동화 웹 서비스'
주제 선정이나 디테일한 기획 부분은 각설하고 내가 맡게 된 백엔드 파트에서 했던 것 중 User 정보 관련 API(회원가입, 로그인, 로그아웃)와 JWT 발급에 대해 설명하고자 한다.
프론트 부분은 따로 만들었기 때문에 API에 대해서만 언급한다.
앱 이름은 accounts로 했다.
Backend/settings.py
(프로젝트 이름을 Backend로 만들었다)
세팅 파일에서 INSTALLED_APPS 부분에 꼭
'accounts',
이걸 추가해야 한다.
accounts/views.py
def signup(request):
if request.method == 'POST':
data = JSONParser().parse(request)
serializer = UserSerializer(data=data)
if serializer.is_valid():
serializer.save()
return JsonResponse(serializer.data, status=201)
return JsonResponse(serializer.errors)
accounts/urls.py
from django.urls import path
from accounts import views
from django.conf.urls import include
app_name = 'accounts'
urlpatterns = [
path('signup', views.signup),
]
accounts/models.py
from django.contrib.auth.models import AbstractUser
from django.db import models
class User(AbstractUser) :
username = models.CharField(max_length=255, unique=True)
email = models.CharField(max_length=200, unique = True)
password = models.CharField(max_length=200)
created_at = models.DateTimeField(auto_now_add=True)
REQUIRED_FIELDS = []
Django는 기본적으로 제공하는 user 모델이 있기 때문에 이를 사용하여 필요한 필드만 수정하고 추가하는 방식으로 사용했다. username = 보통 생각하는 유저 id 로 사용했는데 요즘에는 id 안쓰고 메일만 쓰는 경우도 많아서 그런 부분은
'Django user model custom' 이라는 키워드로 구글링하면 정보를 찾을 수 있을 것이다.
이 이후에
python manage.py makemigration <app 이름>,
python manage.py migration <app 이름>
까지 해줘야 db에 테이블이 생성된다.
accounts/serializers.py
from rest_framework import serializers
from .models import User
class UserSerializer(serializers.ModelSerializer) :
class Meta:
model = User
fields = ['id', 'username', 'email', 'password', 'created_at']
extra_kwargs = {
'password' : {'write_only' : True}
}
def create(self, validated_data):
password = validated_data.pop('password', None)
instance = self.Meta.model(**validated_data)
if password is not None :
instance.set_password(password)
instance.save()
return instance
유저의 비밀번호는 reponse에 들어가면 안되기 때문에 extra_kwargs 부분을 작성하여 response에는 비밀번호를 제외하게 하였고, db에 유저 데이터가 들어갈 때도 비밀번호는 set_password로 암호화하여 저장하였다.
accounts/admin.py
from django.contrib import admin
from .models import User
admin.site.register(User)
accounts/views.py
@csrf_exempt
def login(request):
if request.method == 'POST':
data = JSONParser().parse(request)
search_username = data['username']
password = data['password']
user = User.objects.filter(username=search_username).first()
if user is None:
raise AuthenticationFailed('User not found!')
if not user.check_password(password):
raise AuthenticationFailed('Incorrect password!')
payload= {
'username' : user.username,
'exp' : datetime.datetime.utcnow() + datetime.timedelta(minutes=60),
'iat' : datetime.datetime.utcnow()
}
token = jwt.encode(payload, JWT_SECRET, algorithm = 'HS256').decode('utf-8')
response = JsonResponse({
'message' : 'ok'
})
response.set_cookie(key ='jwt', value= token, httponly=False, samesite='None')
return response
JWT를 발행하여 로그인을 구현했다. token을 발행할 때 여러 값이 필요한데 그 값을 payload에 담는다.
<payload에 들어갈 인자 값 참고>
JWT_SECRET은 .env파일에 설정해두고 토큰 인코딩과 디코딩 할 때 사용할 수 있게 했다.
생성한 토큰을 쿠키에 넣기 위해 set_cookie 함수를 사용해 구현했다.
accounts/urls.py
from django.urls import path
from accounts import views
from django.conf.urls import include
app_name = 'accounts'
urlpatterns = [
path('signup', views.signup),
path('login', views.login),
]
accounts/views.py
@csrf_exempt
def logout(request) :
if request.method == 'POST' :
response = JsonResponse({
"message" : "success"
})
response.delete_cookie('jwt')
return response
delete_cookie 함수를 사용하여 쿠키에서 토큰을 제거하는 방식으로 로그아웃을 구현했다.
accounts/urls.py
from django.urls import path
from accounts import views
from django.conf.urls import include
app_name = 'accounts'
urlpatterns = [
path('signup', views.signup),
path('login', views.login),
path('logout', views.logout),
]
블로그를 쓰면서 참고하면 좋은 것 같은 글을 발견해서 내가 보기 위해 기록함 -> 비밀번호 암호화 및 JWT 토큰 발행