코딩공부/Django

DRF 커스텀 유저 구현하기, access token의 payload 수정 방법

Dong_Devlog 2022. 11. 10. 20:16
커스텀 유저 구현

 

커스텀 유저를 구현하기 위해 공식 문서를 참고하여 코드를 구현해보자.

공식 문서에는 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"
}

https://jwt.io/

 

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