DRF 커스텀 유저 구현하기, access token의 payload 수정 방법
커스텀 유저 구현
커스텀 유저를 구현하기 위해 공식 문서를 참고하여 코드를 구현해보자.
공식 문서에는 email 주소와 생년월일을 필수로 기입하도록 설정되었지만,
생년월일을 빼고 email 주소로 회원가입을 하고 로그인을 할 수 있도록 구현해 볼 것 이다.
https://docs.djangoproject.com/en/4.1/topics/auth/customizing/
Customizing authentication in Django | Django documentation | Django
Django The web framework for perfectionists with deadlines. Toggle theme (current theme: auto) Toggle theme (current theme: light) Toggle theme (current theme: dark) Toggle Light / Dark / Auto color theme Overview Download Documentation News Community Code
docs.djangoproject.com
BaseUserManager의 normalize_email을 통해 이메일 주소의 도메인 부분을 소문자로 지정하여 이메일 주소를 정규화하고 user.set_password를 통해 암호 해싱을 처리하면서 사용자의 암호를 주어진 원시 문자열로 설정한다.
그렇게 일반 유저와 관리자 유저를 생성할 수 있도록 UserManager 클래스를 생성해주고
# models.py
from django.db import models
from django.contrib.auth.models import BaseUserManager, AbstractBaseUser
class UserManager(BaseUserManager):
def create_user(self, email, password=None):
if not email:
raise ValueError('Users must have an email address')
user = self.model(
email=self.normalize_email(email),
)
# normalize_email : 이메일 주소를 정규화
user.set_password(password)
user.save(using=self._db)
return user
# 패스워드를 해싱하여 user_db에 저장
def create_superuser(self, email, password=None):
user = self.create_user(
email,
password=password,
)
user.is_admin = True
user.save(using=self._db)
return user
EmailField 값을 지정해주고 unique=True로 지정해주어 고유 식별자로 사용할 수 있도록 정의해준다.
is_active와 is_admin은 장고의 유저 모델의 필수 필드로 is_active는 사용자가 "활성"으로 간주되는지 여부를 나타내는 BooleanField이다.
USERNAME_FIELD = 'email' 사용자의 username field에 email을 사용하도록 설정해준다
# models.py
class User(AbstractBaseUser):
email = models.EmailField(
verbose_name='email address',
max_length=255,
unique=True,
)
is_active = models.BooleanField(default=True)
is_admin = models.BooleanField(default=False)
objects = UserManager()
USERNAME_FIELD = 'email'
# 사용자의 username field에 email을 사용하도록 설정
REQUIRED_FIELDS = []
# 필수로 작성되어야 하는 field
def __str__(self):
return self.email
@property
def is_staff(self):
return self.is_admin
# 관리자 화면에 로그인 가능 여부
User 모델을 기반으로 serializer를 작성해주고 field로는 __all__ 모든 값을 설정해준다. create 시(회원가입 시) 입력 받은 데이터를 검중해주어야 하기 때문에 validated_data(유효성 검증을 통과한 값)를 기반으로 User 객체를 생성해준다.
simple-jwt 방식으로 토큰인증방식을 사용하여 TokenObtainPairSerializer를 사용하여 토큰 값을 생성할 수 있도록 한다.
# serializer.py
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
from rest_framework import serializers
from users.models import User
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = '__all__'
def create(self, validated_data):
user = super().create(validated_data)
user.set_password(user.password)
user.save()
return user
class CustomTokenObtainPairSerializer(TokenObtainPairSerializer):
@classmethod
def get_token(cls, user):
token = super().get_token(user)
token['email'] = user.email
return token
simple-jwt의 토큰인증방식을 사용하는 방법에 대해서는 공식 문서를 통해 참조.
https://django-rest-framework-simplejwt.readthedocs.io/en/latest/customizing_token_claims.html
Customizing token claims — Simple JWT 5.2.1.post3+gbd4c6ce documentation
Customizing token claims If you wish to customize the claims contained in web tokens which are generated by the TokenObtainPairView and TokenObtainSlidingView views, create a subclass for the desired view as well as a subclass for its corresponding seriali
django-rest-framework-simplejwt.readthedocs.io
APIView 클래스를 이용하여 post 메소드를 구현하여 serializer를 통해 객체화하여 DB에 데이터를 저장할 수 있도록 한다.
# views.py
from rest_framework.views import APIView
from rest_framework import status
from rest_framework.response import Response
from rest_framework_simplejwt.views import TokenObtainPairView
from users.serializers import UserSerializer, CustomTokenObtainPairSerializer
class UserView(APIView):
def post(self, request):
serializer = UserSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response({"message": "회원 가입이 완료되었습니다"}, status=status.HTTP_201_CREATED)
else:
return Response({"message":f"%{serializer.errors}"}, status=status.HTTP_400_BAD_REQUEST)
class CustomTokenObtainPairView(TokenObtainPairView):
serializer_class = CustomTokenObtainPairSerializer
access token의 payload 수정 방법
회원가입과 로그인을 구현하여 포스트맨으로 POST로 JSON형식으로 회원가입을 한 다음 로그인을 하면 access 토큰을 받을 수 있는데, 토큰에는 여러 정보가 담겨 있고 access 토큰에 담겨있는 정보를 확인하기 위해서 jwt.io에 접속하여 access토큰 값을 입력하면 Decoded의 PAYLOAD에 토큰의 정보가 출력된다.
{
"email": "test@test.com",
"password": "qwer1234"
}
JWT.IO
JSON Web Tokens are an open, industry standard RFC 7519 method for representing claims securely between two parties.
jwt.io
PAYLOAD에 토큰의 정보을 수정하기 위해서는 아래와 같이 serializer.py에서 token['email']을 통해 토큰의 정보를 추가하거나 수정할 수 있다.
# serializer.py
class CustomTokenObtainPairSerializer(TokenObtainPairSerializer):
@classmethod
def get_token(cls, user):
token = super().get_token(user)
token['email'] = user.email
token['token_message'] = "test"
return token