본문 바로가기
DEV/Web 개발

Web 개발 :: 파이썬 Django Rest Framework(5) _ CustomUser 등록 및 회원가입

by 올커 2022. 10. 29.

DRF(Django Rest Framework)(5) _ CustomUser 등록 및 회원가입

01. 커스텀 유저 생성하기

 - 유저 생성시 들어가야 하는 정보를 커스터마이징 하려고 한다.  (※ 참고 링크)

   일단 위 참고 링크(* 장고 공식 문서, Customizing authentication in Django)에서 맨 아래쪽 A full example을 보면 아래와 같은 화면을 확인할 수 있다. 코드를 복사해서 가져온 후 입맛에 맞게 커스터마이징 하면 된다.

 - 유저 모델을 장고 프로젝트에서 관리하기 위해 settings.py의 AUTH_USER_MODEL = 'users.User'로 정의한다.


02. 커스텀 유저 Admin에 등록하기

 - Admin 페이지에서 모델을 관리하기 위해 admin.py에 아래와 같이 입력해보았다. 이 때, 괄호 안에는 (User, UserAdmin)으로 쓸 수 없으며 그냥 User 모델만 가져온다. 이는 우리가 모델에 커스터마이징을 했기 때문이다.

from django.contrib import admin
from .models import User

admin.site.register(User)

 - 하지만 현재 상태에서는 패스워드가 해싱되지 않는 문제가 있다. 이 부분도 공식문서를 참고해보면 아래와 같이 제공하고 있음을 확인할 수 있었다.(※ 참고 링크) 아래 내용을 모두 복사하여 admin.py에 붙여넣기 하고, 모델 이름 수정 및 사용하지 않는 항목/필드 삭제(date_of_birth)를 하였다.

# user/admin.py

from django import forms
from django.contrib import admin
from django.contrib.auth.models import Group
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from django.contrib.auth.forms import ReadOnlyPasswordHashField
from django.core.exceptions import ValidationError

from users.models import User


class UserCreationForm(forms.ModelForm):
    password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
    password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)

    class Meta:
        model = User
        fields = ('email',)

    def clean_password2(self):
        # Check that the two password entries match
        password1 = self.cleaned_data.get("password1")
        password2 = self.cleaned_data.get("password2")
        if password1 and password2 and password1 != password2:
            raise ValidationError("Passwords don't match")
        return password2

    def save(self, commit=True):
        # Save the provided password in hashed format
        user = super().save(commit=False)
        user.set_password(self.cleaned_data["password1"])
        if commit:
            user.save()
        return user


class UserChangeForm(forms.ModelForm):
    password = ReadOnlyPasswordHashField()

    class Meta:
        model = User
        fields = ('email', 'password', 'is_active', 'is_admin')


class UserAdmin(BaseUserAdmin):
    form = UserChangeForm
    add_form = UserCreationForm

    list_display = ('email', 'is_admin')
    list_filter = ('is_admin',)
    fieldsets = (
        (None, {'fields': ('email', 'password')}),
        ('Permissions', {'fields': ('is_admin',)}),
    )
    # add_fieldsets is not a standard ModelAdmin attribute. UserAdmin
    # overrides get_fieldsets to use this attribute when creating a user.
    add_fieldsets = (
        (None, {
            'classes': ('wide',),
            'fields': ('email', 'password1', 'password2'),
        }),
    )
    search_fields = ('email',)
    ordering = ('email',)
    filter_horizontal = ()


admin.site.register(User, UserAdmin)
admin.site.unregister(Group)

03. 회원가입과 로그인

 - api를 사용하여 회원가입, 로그인 기능을 구현해본다.

 - 먼저 url 지정을 한다. 사용할 뷰의 이름은 UserView이다.

# users/urls.py

urlpatterns = [
    path('signup/', views.UserView.as_view(), name='user_view'),
    ...
]

 - Serializer를 지정해준다.

# users/serializers.py

from rest_framework import serializers
from users.models import User


class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = '__all__'

 - UserView를 아래와 같이 정의한다.

# users/views.py

from rest_framework import status
from rest_framework.views import APIView
from rest_framework.response import Response

from users.serializers import UserSerializer


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)

 - 현재 상태에서 포스트맨에서 결과를 찍어주면 아래와 같이 에러 메시지를 확인할 수 있다.

 - Body에 요구하는 내용을 적어 다시 send해보면 회원가입이 되어 "가입완료"를 출력한다.

 - 하지만 이렇게 가입한 값을 login에 넣어 send할 경우 아래와 같이 오류메시지가 나온다. 이는 직접 db에 들어가면 확인할 수 있는데, 입력된 password가 해싱이 되지 않고 그대로 저장이 되고 있었기 때문이다.

 - 패스워드에 해싱 처리를 하기위해 serializers.py를 아래와 같이 수정해주었다. create라는 함수가 UserSerializer에 추가되었다. 함수의 내용은 validated_data를 활용하여 user라는 변수를 생성하고, 그 내부의 password를 불러와서 set_password라는 함수를 통해 해싱처리, 그리고 마지막으로 save한 후 리턴해준다. 

# users/serializers.py

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)
        password = user.password
        user.set_password(password)
        user.save()
        return user

 - 새로 아이디를 만든 후 포스트맨에서 signup, login순서로 확인해보면 정상적으로 가입되고, 로그인시 refresh, access 토큰을 넘겨줌을 확인할 수 있다. 수정 부분도 create와 동일하게 생성해주면 된다.

def update(self, validated_data):
        user = super().create(validated_data)
        password = user.password
        user.set_password(password)
        user.save()
        return user

 

 

 

 

 

 

 

반응형

댓글