f-lab-edu / realtor

1 stars 0 forks source link

Token authentication 구현 #15

Closed f-lab-stephen closed 1 year ago

f-lab-stephen commented 1 year ago

목표

현재 Auth 기능이 사용되지 않고 있다. 그러므로 아래 문서를 참조하여 Token Authentication을 구현해 회원 가입, 토큰 발행, 검증 등의 동작을 수행할 수 있게 한다.

태스크

Acceptance Criteria

sanghunjo921 commented 1 year ago

튜토리얼에서 from rest_framework.authtoken.models import Token

token = Token.objects.create(user=...) print(token.key)

이 부분을 어디에 작성할지 고민되네요. 세팅 파일에 작성을 해야 할까요? 아니면 유저를 위한 토큰을 만드는 부분이기에 유저 디렉토리에 반영해야 할까요?

f-lab-stephen commented 1 year ago

튜토리얼에서 언급한 부분은 Token 오브젝트를 User마다 만들어줘야 한다는 걸 알려주기 위한 것이고, 실제로는 그것을 회원가입 시점에 하게 됩니다. 링크해 드린 블로그에서 회원가입하는 부분을 살펴 보세요. 토큰 생성하는 부분이 있습니다.

f-lab-stephen commented 1 year ago

해당 블로그에 부분부분 오타가 좀 있는 것 같네요. 그대로 복붙하지 마시고 흐름을 읽고 올바른 코드로 다시 짠다고 생각하시면 베스트겠습니다!

sanghunjo921 commented 1 year ago

AttributeError: Manager isn't available; 'auth.User' has been swapped for 'users.User' 에러가 발생했는데 제 생각에는 현재 유저 모델 자체가 abstractuser로부터 상속받고 있으며 제 기억이 맞다면 abstractuser에 이미 auth가 들어가 있어서 발생하는거 같습니다.

제 생각이 맞다면 RegistrationSerializer안에서 model = user 정의할때 user가 저가 커스텀한 유저가 되는걸까요?

sanghunjo921 commented 1 year ago

현재 회원가입 페이지 구현하면서 예제랑 다른부분이 많아서 다른 다큐먼트 참고하는 중 입니다. 찾아보던 중 rest_auth를 이용하기도 하네요

sanghunjo921 commented 1 year ago

slack overflow 참고하니 세팅에 AUTH_USER_MODEL = 'users.User' 정의되어 있기에 이걸 from django.contrib.auth.models import User 이거로 from django.contrib.auth import get_user_model 교체했습니다.

f-lab-stephen commented 1 year ago

slack overflow 참고하니 세팅에 AUTH_USER_MODEL = 'users.User' 정의되어 있기에 이걸 from django.contrib.auth.models import User 이거로 from django.contrib.auth import get_user_model 교체했습니다.

훌륭합니다! User 모델 참조는 그 방법으로 하는 것이 올바릅니다.

sanghunjo921 commented 1 year ago

루트 url

authentication folder를 만들어서 그 안에 serializers.py, urls.py, views.py 파일들 만들고 urls.py에

이런식으로 현재 제 코드 구조와 비슷하게 만들었는데 포스트맨으로 post request 날리면 page not found 에러가 뜨네요.. 요청은 http://localhost:8000/api-register-auth/로 날렸습니다.

sanghunjo921 commented 1 year ago

terminal에서 httpie로 테스트 하려고 하는데

http --json POST http://localhost:8000/api/auth/register username="sanghun" email="salr921@gmail.com" first_name="sanghun" last_name="jo" password="1234"{ "status": { "code": "200 ok", "message": "user created" }, "token": "b4784f96c3c65387bc8ea6463d5d4658cb32b0ac", "user: { "id": 2. "first_name": "sanghun", "last_name": "jo", "username": "sanghun", "email": "salr921@gmail.com", "is_active": true, "is_staff": true, }}

이런식으로 날리니깐 dquote로 들어가지네요

sanghunjo921 commented 1 year ago

tutorial views.py에서 if registration_class.is_valid(): user = registration_serializer.save() token = Token.objects.create(user=user) 여기서 registration_class.is_valid(): 이것도 오타일까요? registration_class가 정의되지 않았는데 쓰여있길래 오타인지 아니면 이게 장고에서 import했던 애들중에 지원해주는 애가 있어서 쓰여져 있는지 모르겠네요.

registration_serializer가 valid하면 유저에 저장 후 토큰 발행일꺼 같긴한데 ... serializer로 바꿔서 해보니까 AttributeError: module 'rest_framework.serializers' has no attribute 'errors' 새로운 에러가 뜨는군요 .....

sanghunjo921 commented 1 year ago

찾아보니 from django.core import serializers as core_serializers를 써야 하는거 같긴한데 블로그상이랑 달라서 혼동입니다 😅

f-lab-stephen commented 1 year ago

튜토리얼 상에서 사용한 registration_class는 오류입니다. is_valid() 메서드를 사용하는 거면 Serializer겠네요. 정의하신 serializer (맥락으로 봤을 때 registration_serializer)를 사용하시면 되겠습니다. 맨 아래는 errors를 성급하게 사용한 게 아닌가 싶네요. errors property는 rest_framework.serailizers.Serializer에 있으니까요.

sanghunjo921 commented 1 year ago

예. errors 지우고 날려보니까 { "status": "203 \ NON AUTHORITATIVE INFORMATION" }라고 뜨네요

registration_serializer.is_valid():이게 valid하지 않은거 같은데 저가 포스트맨으로

스크린샷 2023-04-07 오후 5 32 44

이런식으로 날렸어요

sanghunjo921 commented 1 year ago
스크린샷 2023-04-07 오후 5 34 16

저가 정의한 registrationSerializer 참고해서 is_active & is_staff 제외하고 패스워드 추가해서 날리니까 module 'rest_framework.serializers' has no attribute 'data' 에러가 뜨네요

일시적인 오류였나 봅니다. 다시 날려보니까 터미널에서는 status 200뜨는데 포스트맨에서는 오류로 표시되네요. 정상적이라면 토큰이 나와야하는데 serializer쪽에 문제가 있는거 같아서 일단 찾아볼게요

현재 만들어진 serializer의 모습입니다. RegistrationSerializer(data=<QueryDict: {'first_name': ['sanghun'], 'last_name': ['jo'], 'username': ['salr921'], 'email': ['salr921@gmail.com'], 'password': ['abcd']}>): id = IntegerField(label='ID', read_only=True) username = CharField(helptext='Required. 150 characters or fewer. Letters, digits and @/./+/-/ only.', max_length=150, validators=[, <UniqueValidator(queryset=User.objects.all())>]) first_name = CharField(allow_blank=True, max_length=150, required=False) last_name = CharField(allow_blank=True, max_length=150, required=False) email = EmailField(allow_blank=True, label='Email address', max_length=254, required=False) password = CharField(max_length=128, write_only=True) is_active = BooleanField(help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', label='Active', required=False) is_staff = BooleanField(help_text='Designates whether the user can log into this admin site.', label='Staff status', required=False)

sanghunjo921 commented 1 year ago

is_Valid() 이후 serializers.errors 프린트 결과 {'username': [ErrorDetail(string='A user with that username already exists.', code='unique')]}

따라서 serializer는 정상적으로 보입니다. 하지만 존재하지 않은 유저네임으로 다시 날렸더니 id쪽 에러 발생한것을 보니 view쪽이 문제였군요

views.py", line 33, in post "id": serializers.data["id"], ^^^^^^^^^^^^^^^^ 튜토리얼에서는 저런식으로 코드가 작성되었는데 제 생각에는 이전에 발생한 errors와 같은 문제같습니다.

sanghunjo921 commented 1 year ago
스크린샷 2023-04-07 오후 5 57 33

굳이 필요없는 부분 다 지워버리고 다시 날렸더니 의도한데로 토큰을 주네요! 이게 맞는걸까요?