유저 확장 Part.1

김동현·2024년 3월 17일

Django

목록 보기
2/6

Custom UserModel

Django 프레임워크에는 추상화된 User 모델과 인증 절차가 존재한다.
Django가 제공하는 기본적인 인증으로 충족되지 않는 요구사항이 있을 때 프로젝트에서 인증을 커스텀하기 위해 확장하거나 대체되어야 하는 필드들이 존재한다.

📝 JWT(Json Web Token)를 활용한 인증 절차를 구현해보기 위해
AbstractBaseUser, PermissionsMixin, BaseUserManager를 활용해보자

The easiest way to construct a compliant custom user model is to inherit from AbstractBaseUser. AbstractBaseUser provides the core implementation of a user model, including hashed passwords and tokenized password resets. You must then provide some key implementation details:

AbstractBaseUser 클래스는 비밀번호 설정에 대한 핵심 구현을 제공합니다.

class AbstractBaseUser(models.Model):
	# 비밀번호
    password = models.CharField(_("password"), max_length=128)
    # 마지막 로그인 날짜
    last_login = models.DateTimeField(_("last login"), blank=True, null=True)
	
    # 활성화 여부
    is_active = True

	# 해당 부분에 Required로 담을 필드를 넣어줍니다.
    REQUIRED_FIELDS = []

    # Stores the raw password if set_password() is called so that it can
    # be passed to password_changed() after the model is saved.
    _password = None
    ...

PermissionsMixin는 Django의 권한 프레임워크를 커스텀 유저에 쉽게 포함할 수 있도록 제공되는 추상 클래스입니다.

class PermissionsMixin(models.Model):
    """
    Add the fields and methods necessary to support the Group and Permission
    models using the ModelBackend.
    """

    is_superuser = models.BooleanField(
        _("superuser status"),
        default=False,
        help_text=_(
            "Designates that this user has all permissions without "
            "explicitly assigning them."
        ),
    )
    ...

    class Meta:
        abstract = True

BaseUserManager Custom 유저 모델을 위한 관리자도 정의해야합니다.

Writing a manager for a custom user model¶
You should also define a custom manager for your user model. If your user model defines username, email, is_staff, is_active, is_superuser, last_login, and date_joined fields the same as Django’s default user, you can install Django’s UserManager; however, if your user model defines different fields, you’ll need to define a custom manager that extends BaseUserManager providing two additional

커스텀 유저 모델에서 is_staff, is_active 등 Django의 기본 사용자 이외의 추가적인 필드를 정의하는 경우 BaseUserManager도 확장하여 아래 이미지 두 가지 추가 메서드(create_user, create_superuser)를 제공해주어야 합니다.

각 메서드는 사용자 이름 필드와 추가된 모든 필수 필드를 인수로 받아들여야 합니다.
Django Docs에서의 예시는 사용자이름 필드 -> Email Setting, 생년월일 필드가 Required이기 때문에 email, date_of_birth를 매개변수로 받는 것을 확인할 수 있습니다.

✅ objects, USERNAME_FIELD, REQUIRED_FIELDS 지정
BaseUserManager를 상속받아 확장한 Custom Manager를 확장 유저 모델의 objects로 할당하여 줍니다.
이를 통해 User 정보를 가져오는 ORM을 상용할 때 CustomUserManager가 사용됩니다.

USERNAME_FIELD는 유저를 식별하기 위한 고유한 값으로 들어가야 합니다.

class MyUser(AbstractBaseUser):
	# unique=True 
    identifier = models.CharField(max_length=40, unique=True)
    ...
    USERNAME_FIELD = "identifier"

로그인을 위해 username 특정 필드로 커스텀 할 수 있습니다.
USERNAME_FIELD 프로퍼티에 사용하고 싶은 필드를 적용해주시면 됩니다.

# 헬퍼 클래스 지정
objects = CustomUserManager()

# 사용자의 username field는 email으로 설정 (이메일로 로그인)
USERNAME_FIELD = 'email'

# 사용자의 username field는 phone으로 설정 (전화번호로 로그인)
USERNAME_FIELD = 'phone'

REQUIRED_FIEDLS에 필수값을 할당하면 django-admin createsuperuser 명령으로 user를 만들 때 Prompted와 상호 작용하기 위해 필요한 목록을 입력받을 수 있도록 지정해 줄 수 있습니다.

class MyUser(AbstractBaseUser):
    ...
    date_of_birth = models.DateField()
    height = models.FloatField()
    ...
    REQUIRED_FIELDS = ["date_of_birth", "height"]

⚠️ USERNAME_FILED와 Password 필드는 항상 입력되도록 유도되기 때문에 포함되지 않아도 괜찮습니다.

✅ setting.py 설정
마지막으로 setting.py의 AUTH_USER_MODEL 설정을 사용하여 확장한 커스텀 유저 모델을 프로젝트의 기본 사용자 모델로 지정해줍니다.

# settings.py
# user 앱에서 내가 설정한 User를 사용하겠다고 설정.
AUTH_USER_MODEL = 'custom_user.CustomUser'

Code

from django.db import models
from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin, BaseUserManager


class CustomUserManager(BaseUserManager):
    def create_user(self, email, password, **kwargs):
        """
        주어진 이메일, 비밀번호 등 개인정보로 User 인스턴스 생성
        """
        if not email:
            raise ValueError('Users must have an email address')
        user = self.model(
            email=email,
        )
        user.set_password(password)
        user.save(using=self._db)
        return user

    def create_superuser(self, email=None, password=None, **extra_fields):
        """
        주어진 이메일, 비밀번호 등 개인정보로 User 인스턴스 생성
        단, 최상위 사용자이므로 권한을 부여
        """
        superuser = self.create_user(
            email=email,
            password=password,
        )

        superuser.is_staff = True
        superuser.is_superuser = True

        superuser.save(using=self._db)
        return superuser


# AbstractBaseUser를 상속해서 유저 커스텀
class CustomUser(AbstractBaseUser, PermissionsMixin):
    email = models.EmailField(
        'Email',
        max_length=60,
        unique=True,
        null=False,
        blank=False,
        help_text='Email Field'
    )
    is_active = models.BooleanField(
        null=False,
        blank=False,
        default=True,
        help_text='활성화 상태 여부입니다.'
    )
    is_staff = models.BooleanField(
        null=False,
        blank=False,
        default=False,
        help_text='Staff 여부입니다.'
    )
    created_at = models.DateTimeField(
        null=False,
        blank=False,
        auto_now_add=True,
        help_text='생성된 날짜입니다.'
    )
    updated_at = models.DateTimeField(
        null=False,
        blank=False,
        auto_now=True,
        help_text='업데이트 된 날짜입니다.'
    )

    # 헬퍼 클래스 사용
    objects = CustomUserManager()

    # 사용자의 username field는 email으로 설정 (이메일로 로그인)
    USERNAME_FIELD = 'email'

    def __str__(self):
        return self.email

    def get_short_name(self):
        return self.email
#settings.py
AUTH_USER_MODEL = 'custom_user.CustomUser'

참고자료

profile
달려보자

0개의 댓글