TIL # 55 : [Django] 인스타그램 회원가입 및 로그인 엔드포인트 + error 모음

셀레스틴 허·2021년 2월 4일
1
post-thumbnail

westagram이라는 django project, 그리고 user라는 django app을 만든 상태다.

1. 회원가입 구현


인스타그램 회원가입 페이지 구조 파악

1.1) 사용자의 입력값

  1. 휴대폰 번호 또는 이메일 입력
  2. 이름
  3. 유저네임
  4. 비밀번호

휴대폰 번호 및 이메일은 다른 사용자와 중복이 안되어야(unique) 하며 유저네임 또한 중복되면 안된다. 비밀번호는 8자 이상만 가능하다.

1.2) 백엔드가 해야 하는 일 + 나의 추가 조건

  1. 회원가입시 입력하는 휴대폰 번호는 한국 전화번호 (000-0000-0000)이어야 하며 하이픈을 꼭 포함해야 한다. 휴대폰 번호는 기존에 DB와 확인하며 같은 휴대폰 번호가 있는지 검사해야 한다.
  2. 이메일은 중복되면 안된다. 그러므로 휴대폰 번호와 동일하게 DB를 확인하며 같은 이메일이 있는지 봐야한다.
  3. 유저네임도 중복되면 안된다. 똑같이 DB를 확인해야 한다.
  4. 비밀번호는 최소 문자 1개, 숫자 1개, 특수문자가 포함되면 Valid Password로 승인된다.

1.3) 코드

1.3.1) models.py

  1. 중복이 되면 안되는 코드는 unique=True를 줘서 고유값으로 설정한다.
  2. 휴대폰 번호 또는 이메일을 입력할 수 있으니 null=True를 적용해 하나는 null값이 들어갈 수 있게 설정한다.
  3. created_atauto_now_add=True를 적용해 생성시 바로 DateTime이 붙는 방식으로, modified_atauto_now를 줘서 수정하는 시간의 DateTime이 붙도록 만들었다.

mysql로 가서 데이터베이스를 하나 생성한다. 그리고 해당 데이터베이스 이름 및 비밀번호를 settings.py에 입력한다.

manage.py가 있는 디렉토리로 가서 python manage.py makemigrations userpython manage.py migrate user를 해서 데이터베이스에 칼럼을 만든다.

1.3.2) urls.py

westagram.urls

include 함수를 이용해서 리펙토링한다. 그리고 include 함수 안에 user.urls를 써서 user앱 url을 관리한다.

user.urls

user 앱 안에 urls.py를 생성해 as_view()를 활용해 해당되는 view를 가져온다. 회원가입을 signup 그리고 로그인을 signin으로 url을 설정했다.

1.3.3) views.py

import

  1. 일단 json, re(파이썬 정규 표현식을 지원하기 위한 친구), brcypt와 jwt(로그인시 토큰 발행을 위한 친구)등 파이썬 모듈을 import한다. 그리고 기타 JsonResponse, HttpResponse, View, Q 등 필요한 장고 모듈을 import한다.

  2. 내가 만든 user 앱의 models를 가져온다.

  3. westagram project에서 my_settings안에 있는 SECRET_KEY, ALGORITHM을 가져온다. 추후 로그인 기능 구현시 필요하다..

validation 정규표현식

  1. email_regex, password_regex, phone_regex라는 정규 표현식 validation 조건을 만든다.

  2. 추후 적용하기 위해 최소 비밀번호 길이(MINIMUM_PASSWORD_LENGTH) 변수를 선언한다.

class SignUpView

  1. json.loads를 써서 파이썬이 읽을 수 있는 딕셔너리 데이터 타입으로 변환한다.
  2. 프론트에서 받은 json 바디 속 데이터들을 하나씩 변수 안에 넣는다.
  3. 사용자가 name, phone, username, password를 입력했는지 확인한다.
  4. email, username이 DB안에 이미 존재하는지 확인한다. 이미 존재하면해당 email, username은 쓸 수 없다.
  5. email, password, phone이 앞서 선언한 validation 조건과 맞는지 확인한다. 
  6. hashed_password 변수를 선언해서 솔트로 소금친 hashed 된 비밀번호를 만든다.
  7. 만약 앞서 선언한 if statement들을 다 통과할 시 User 객체 안에 새로운 nmae, email, phone, password, username을 create한다.
  8. 그리고 {"message" : "SUCCESS"}를 return 한다.

2. 로그인 구현


인스타그램 로그인 페이지 구조 파악

2.1)사용자의 입력값

인스타그램 로그인을 확인해보면 입력창은 총 2개다. 유저는:
1. 휴대폰 번호, 유저네임, 이메일 중 1개 입력
2. 그리고 비밀번호를 입력해야지 로그인할 수 있다

2.2) 백엔드가 해야 하는 일

우리는 사용자가 휴대폰 번호, 유저네임, 이메일 중 어떤 값을 입력할지 모른다. 3개 중 1개의 값만 받으면 되기 때문이다. 즉 이들 중 1개를 받았을 때, 그것이:
1. (사용자가 입력한) 휴대폰 번호, 유저네임, 이메일 DB에 존재하는지
2. (사용자가 입력한) 비밀번호는 우리가 암호화시킨 비밀번호와 일치하는지
3. (사용자) 정보 일치 확인 후 access token 발행해야 한다.

2.3) 코드

2.3.1) urls.py

SignUp과 똑같이 urlspatterns안에 /singin과 SingInView를 연결한다.

2.3.2) models.py

SignUp과 똑같은 models.py에 User class를 쓴다.

2.3.3) views.py

class SignInView

위에 선언한 class SignUpView 밑에 위치한 코드다.
1.. json.loads를 써서 파이썬이 읽을 수 있는 딕셔너리 데이터 타입으로 변환한다.
2. 프론트에서 받은 json 바디 속 데이터들을 하나씩 변수 안에 넣는다.
3. 사용자가 email, phone, username, password를 입력했는지 확인한다. 파이썬의 .get()을 활용해 사용자가 어느 값을 입력 안할 시 None을 받을 수 있게 data.get('something_in_request_body', None)와 같이 입력한다.
4. 만약 email, username, phone 중 한 값 + 비밀번호를 같이 넘기지 않을 시 REQUIRED_FIELD가 뜨게끔 JsonMessage를 설정한다.
5. DB 안에 사용자가 입력한 email, username, phone 중 한 값이 존재하는지, 그리고 존재한다면 그 값을 .get()한다.

filter는 여러값을 get는 하나의 값만 가져올 수 있다.

  1. 만약 user가 존재한다면 해당 user의 비밀번호를 DB에 있는 user의 비밀번호와.checkpw 함수로 확인한다.
  2. 만약 양쪽 비밀번호가 일치하면 access_token을 발행한다.

Error

Error 목록:

1. ValueError : Invalid salt()

binaryfield로 설정안해서 나타나는 문제라고 생각하고 charfield로 바꾸고 다시 migration을 진행했다. 그러나 다른 Error가 떴다... 사태가 더 심각해지기 전에 charField로 다시 바꾸고 구글링을 해봤다. stackoverflow에서 hashed_password를 데이터베이스에 load하기 전에 decode를 해야 한다고 써져있었다. 그렇게 코드를 수정하니 성공적으로 hashed_password를 받을 수 있었다.

hashed_password = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt()).decode('utf-8')

hashed_password가 성공적으로 나왔다!

🖤encode(), decode()의 차이🖤
encode(): byte 타입으로 변환. decode()는 string 타입으로 변환한다.

2. email validation


'@'를 뺀 이메일 패턴을 입력할 시 email_regex.search(email)으로 내가 선언한 email = data['email']과 email validation 변수 email_regex가 search 되는지 확인한다.

🖤search vs match의 차이🖤
https://docs.python.org/3/library/re.html#search-vs-match

3. dquote -> quotation mark 문제

http 요청을 보낼시 자주 뜨는 에러다. 보통 복붙해서 생기는 quotation mark 문제다.

4. Queryset has no id

Queryset로 리턴된 useruser.id로 뽑으려고 했을 때 나타난 에러다. get으로 id를 구하던지 아니면 특정 index로 뽑아야 한다.

5. TypeError: not JSON serializable

json 형태 즉 딕셔너리로 값을 안 넘겼을 때 나는 에러다.

6. django.db.utils.IntegrityError

여러 값을 입력해야하는 객체에게 하나의 값을 넣어 계속 create할 때 발생하는 에러다.

오류 코드:

User.objects.create(name=name)
User.objects.create(email=email)
User.objects.create(phone=phone)
User.objects.create(password=hashed_password)
User.objects.create(username=username)

오류 에러:

수정 코드:

User.objects.create(
    name     = name, 
    email    = email, 
    phone    = phone,
    password = hashed_password, 
    username = username
)

성공:

정말 바보같은 실수라 올리기 뭐하지만.. 누군가는 같은 실수를 하니까 ^^...
p.s. 에러 잡아주신 성준님께 무한 감사를..🙏

결론 ㅣ 설 연휴 동안 장고쉘만 하자...

profile
Software Developer / 고통은 필연, 괴로움은 선택

2개의 댓글

comment-user-thumbnail
2021년 2월 4일

와우... 민젤.. 시간을 갈아넣은 정성스런 블로깅.. 잘봤습니다!
나도 전체적인 플로우 한번 정리해봐야겠네요!ㅋㅋㅋㅋ

1개의 답글