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
'DEV > Web 개발' 카테고리의 다른 글
Web 개발 :: 파이썬 Django Rest Framework(6) _ token, permission (0) | 2022.10.30 |
---|---|
파이썬/머신러닝 웹 프로그래밍 :: 10월 다섯째주 WIL #09 (0) | 2022.10.29 |
Web 개발 :: Django 머신러닝 프로젝트 Code Review _ User_TIL#40 (0) | 2022.10.29 |
Web 개발 :: Django 개발 중 소소하게 알게된 점 _ User_TIL#39 (0) | 2022.10.28 |
Web 개발 :: 파이썬 Django Rest Framework(4) _로그인 방식 및 jwt 토큰 (0) | 2022.10.28 |
댓글