
DRF로 회원가입을 할 때, dj_rest_auth와 all_auth를 함께 사용하는데 이유가 궁금해서 GPT에게 물어봤습니다. (‘•̀ ▽ •́ )✎
django-allauth는 포괄적인 인증 및 사용자 관리 기능을 제공하고, dj-rest-auth는 이를 RESTful API로 노출합니다. 이로 인해 웹 애플리케이션과 모바일 애플리케이션 모두에서 동일한 인증 백엔드를 사용할 수 있습니다.
django-allauth의 소셜 로그인 기능을 dj-rest-auth와 함께 사용하여, REST API를 통해 소셜 로그인 기능을 쉽게 구현할 수 있습니다.
django-allauth의 강력한 이메일 인증 및 비밀번호 관리 기능을 활용하면서, dj-rest-auth를 통해 이러한 기능을 API로 노출할 수 있습니다.
두 패키지 모두 커스터마이징이 용이하며, 필요한 경우 시리얼라이저, 뷰, 폼 등을 쉽게 확장하거나 수정할 수 있습니다.
'API'로 회원가입을 구현할 때는 두 패키지가 상호보완적임을 알 수 있었습니다!
공식 홈페이지에서는 dj_rest_auth를 이렇게 소개하고 있습니다.
dj-rest-auth는 사용자 등록 및 인증 작업(all_auth)을 처리하기 위한 일련의 REST API 엔드포인트를 제공한다.
all_auth도 django.cotrib.auth와 정확히 어떤 차이가 있는지 정확히 모르겠어서 공식 홈페이지 문서에서 Introduction을 읽어 보았습니다.

django.cotrib.auth은 로컬 인증만 지원하고
all auth는 로컬 인증과 소셜 인증 모두 지원하여 두 인증 간의 흐름을 원할하게 하는 것이 가장 큰 차이였습니다.⎝ᑒ⎠
🔑 종합 계정 기능: 여러 인증 방식을 지원합니다 (예: 사용자 이름 또는 이메일로 로그인). 또한, 다양한 계정 확인 전략을 지원합니다 (확인 없음부터 필수 이메일 확인까지).
👥 소셜 로그인: 외부 아이덴티티 제공자를 통해 로그인합니다.
🔒 개인 정보 보호: 계정 열거 방지를 제공하여, 누군가가 이미 계정을 가지고 있는지 여부를 확인할 수 없게 합니다.
🧩 맞춤형: 개발자는 핵심 기능을 특정 요구 사항에 맞게 맞춤 설정할 수 있습니다. 어댑터 패턴을 사용하여 원하는 지점에서 개입할 수 있습니다.
allauth.account : 정규(사용자 이름 및/또는 이메일 기반)계정과 관련된 기능이 구현
allauth.socialaccount : 소셜 계정과 관련된 기능이 구현
allauth.mfa : 다중 요소 인증과 관련된 기능이 구현
account_api_v1 = [
path("register/", api.CustomResisterAPIView.as_view(), name="register"),
]
기존 username이 아닌 email 로그인은 현재 프로젝트의 요구사항입니다.
이를 해결하기 위해 기본 User 모델의 확장과 mangers.py를 통한 사용자 정의 objects가 필요합니다.(Customizing authentication in Django)
Django의 모든 모델은 기본적으로 하나의 관리자를 가지고 있습니다.
이 기본 관리자는 objects라는 이름으로 제공됩니다.(models.Manager 클래스의 인스턴스)
모델 클래스에 특별히 다른 관리자가 정의되지 않으면, Django는 기본 관리자인 objects를 사용합니다.
managers.py는 이 objects(기본관리자)를 새롭게 정의하기 위해 사용됩니다.
요구사항에 맞춰 User 모델의 objects를 새롭게 managers.py를 통해 정의합니다.
class UserManager(BaseUserManager):
def create_user(self, email, password, **extra_fields):
if not email:
raise ValueError(_("The Email must be set"))
email = self.normalize_email(email)
user = self.model(email=email, **extra_fields)
user.set_password(password)
user.save()
return user
def create_superuser(self, email, password, **extra_fields):
extra_fields.setdefault("is_staff", True)
extra_fields.setdefault("is_superuser", True)
extra_fields.setdefault("is_active", True)
if extra_fields.get("is_staff") is not True:
raise ValueError(_("Superuser must have is_staff=True."))
if extra_fields.get("is_superuser") is not True:
raise ValueError(_("Superuser must have is_superuser=True."))
return self.create_user(email, password, **extra_fields)
작성한 managers.py의 create_user와 create_superuser 메서드를 통해
이제 기존 username이 아닌 email과 pwd를 입력받아 user 인스턴스 를 생성할 수 있습니다.
class CustomUser(AbstractUser):
username = None
email = models.EmailField(_("email address"), unique=True)
full_name = models.CharField(max_length=4)
birth_date = models.DateField(null=True, blank=True)
USERNAME_FIELD = "email"
REQUIRED_FIELDS = []
objects = UserManager()
def __str__(self):
return self.email
email 로그인은 기존 Uesr 모델에 없는 필드이고 이를 필드로 추가하기 위해서는 모델의 확장이 필요합니다.
AbstractUser을 상속받아 User 모델을 확장하고 현재 프로젝트의 회원가입 시 필요한 입력 필드이지만 기존의 User 모델에 없던 email 필드 외에 full_name과 birth_date필드도 추가해 주었습니다.
AUTH_USER_MODEL = 'accounts.User'
마지막으로 확장한 User 모델을 기본 인증 모델로 사용하기 위해 settings.py에서 확장한 User 모델을 지정합니다.
현재 프로젝트에서 PM이 기획한 회원가입 필요 입력정보는 다음과 같습니다.
class CustomRegisterSerializer(RegisterSerializer):
username = None
full_name = serializers.CharField()
birth_date = serializers.DateField()
def save(self, request):
user = super().save(request)
user.full_name = self.validated_data.get("full_name")
user.birth_date = self.validated_data.get("birth_date")
user.save()
return user
dj_rest_auth의 RegisterSerializer 기본 필드는 username, email, password 1,2 입니다.
새롭게 CustomRegisterSerializer를 생성하여 full_name, birth_date 필드 또한 입력받아 저장할 수 있게하였습니다.
class CustomResisterAPIView(RegisterView):
serializer_class = CustomRegisterSerializer
마지막으로 새로 정의한 serializer를 사용하기 위해 RegisterView를 상속받아 새롭게 CustomResisterAPIView를 생성하였고 정의한 CustomRegisterSerializer를 serializer_class에 지정하였습니다.


RegisterSerializer를 재정의하면서 save메서드와 RegisterView의 perform_create의 차이를 정확히 모르겠어서 내용을 정리합니다!
데이터 유효성 검사를 마친 후 객체를 생성하거나 DB에 저장
CreateAPIView에서 객체를 생성할 때 호출되며, Serializer의 save 메서드를 호출합니다.
perform_create를 재정의하면 객체 생성 후 추가적인 작업을 정의할 수 있다
RegisterView의 RegisterSerializer의 save로 바로 객체 생성 및 저장을 하느냐 RegisterView에서 perform_create를 재정의하여 save 시 추가적인 로직을 수행할 것이냐의 차이 였습니다.
실제로 perform_create의 소스코드를 보면 더욱 이해가 쉽습니다.
def perform_create(self, serializer):
# serializer의 save 메서드를 호출하여 사용자 인스턴스를 생성합니다.
user = serializer.save(self.request)
# 이메일 인증 설정이 'MANDATORY'가 아닌 경우에만 추가 작업을 수행합니다.
if allauth_account_settings.EMAIL_VERIFICATION != allauth_account_settings.EmailVerificationMethod.MANDATORY:
# JWT 사용 설정이 활성화된 경우, 액세스 토큰과 리프레시 토큰을 생성합니다.
if api_settings.USE_JWT:
self.access_token, self.refresh_token = jwt_encode(user)
# 세션 로그인이 활성화되지 않은 경우, 토큰 인증을 사용합니다.
elif not api_settings.SESSION_LOGIN:
# 세션 인증이 활성화되지 않았으므로, 토큰 인증을 사용해야 합니다.
# 이 경우, 토큰 생성 함수를 호출하여 사용자와 연관된 토큰을 생성합니다.
api_settings.TOKEN_CREATOR(self.token_model, user, serializer)