- 생성한 사용자 클래스를 불러옵니다. 한 번에 모든 클래스를 import 해서는 안됩니다. 내가 사용할 클래스를 정확히 지칭해주세요
- 인스타그램에 회원가입 할 때에는 사용자 계정으로 이메일을 필수로 필요합니다.
- 인스타그램에 회원가입 할 때에는 비밀번호도 필수로 필요합니다.
- 회원가입 할 때 핸드폰 번호와 닉네임도 추가로 저장합니다.
- 이메일이나 패스워드 키가 전달되지 않았을 시, {"message": "KEY_ERROR"}, status code 400 을 반환합니다.
- 회원가입시 이메일을 사용할 경우, 이메일에는 @와 .이 필수로 포함되어야 합니다. 해당 - 조건이 만족되지 않을 시 적절한 에러를 반환해주세요. 이 과정을 email validation이라고 합니다.
- 회원가입시 비밀번호는 8자리 이상이어야만 합니다. 해당 조건이 만족되지 않을 시, 적절한 에러를 반환해주세요. 이 과정을 password validation이라고 합니다.
- 회원가입시 서로 다른 사람이 같은 전화번호나 사용자 이름, 이메일을 사용하지 않으므로 기존에 존재하는 자료와 중복되어서는 안됩니다. 적절한 에러를 반환해주세요.
- 회원가입이 성공하면 {"message": "SUCCESS"}, status code 201을 반환합니다.
- [추가 구현 사항] -> email validation 또는 password validation 과정에서 정규식을 사용해보세요.
우선 django 프로젝트를 하기 위해 앞서 배웠던 초기세팅을 해주시면 됩니다.
장고 프로젝트 초기세팅 & 가상환경 설정
하지만 몇가지 추가사항이 있습니다.
CORS
관련 몇가지 추가사항이 있습니다.
CORS
플러그인 설치pip install django-cors-headers
ALLOWED_HOSTS 추가
# settings.py
ALLOWED_HOSTS = ['*']
내 서버에 다른 컴퓨터가 접속을 시도합니다. 무분별한 접속을 차단하기 위해 우리는 특정 아이피 주소를 가진 접속만을 허용하기 위해서 ALLED_HOSTS를 수정합니다. 보통 허용하고자 하는 아이피 주소만을 입력하지만, 프로젝트 진행시 여러 아이피 주소를 허용해야 하기에 *을 이용하여 모두 허용해줍니다.
INSTALLED_APPS에 corsheaders 추가
# settings.py
INSTALLED_APPS = [
#'django.contrib.admin',
#'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'corsheaders',
]
프론트엔드와 통신을 할 때에는 서로 다른 port로 접속을 시도합니다. 이를 허용해주기 위하여 INSTALLED_APPS에 기존 설정 사항 아래에 corsheaders를 추가해줍니다.
middleware 추가
# settings.py
MIDDLEWARE = [
...
'corsheaders.middleware.CorsMiddleware',
]
settings.py 제일 아래 다음 내용 추가
# settings.py
##CORS
CORS_ORIGIN_ALLOW_ALL=True
CORS_ALLOW_CREDENTIALS = True
CORS_ALLOW_METHODS = (
'DELETE',
'GET',
'OPTIONS',
'PATCH',
'POST',
'PUT',
)
CORS_ALLOW_HEADERS = (
'accept',
'accept-encoding',
'authorization',
'content-type',
'dnt',
'origin',
'user-agent',
'x-csrftoken',
'x-requested-with',
)
여기까지가 장고 프로젝트를 시작하기 위한 초기 세팅입니다. 기능 구현을 시작해보겠습니다.
우선 회원가입, 로그인을 구현하기 위햇 app을 만들어야합니다. 그 이름은 user
또는 account
가 적당하겠습니다. 저는 user
로 만들어 보겠습니다.
회원가입 기능 구현 app 만들기
python manage.py startapp user
회원가입 user 테이블 만들기
from django.db import models
class User(models.Model):
email = models.EmailField(max_length=50)
password = models.CharField(max_length=300)
phone_number = models.CharField(max_length=20, null=True)
nickname = models.CharField(max_length=20, null=True)
class Meta:
db_table = 'users'
회원가입에는 이메일과 패스워드 값이 필수이고 전화번호와 닉네임은 추가사항이니 다음과 같이 테이블 클래스를 models.py
에 작성하였습니다. 이후 마이그레이션을 통해 데이터베이스에 테이블을 생성하겠습니다.
마이그레이션하여 테이블 생성
python manage.py makemigrations
python manage.py migrate
views.py
import json, re, bcrypt, jwt
from django.core.exceptions import ObjectDoesNotExist
from django.http import JsonResponse
from django.db import IntegrityError
from django.views import View
from westagram.settings import SECRET_KEY, ALGORITHM
from .models import User
class UserSignUp(View):
def post(self, request):
email_regex = '^[a-zA-Z0-9+-_.]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$'
data = json.loads(request.body)
signup_data = User.objects
hashed_pw = bcrypt.hashpw(data['password'].encode('utf-8'), bcrypt.gensalt())
decoded_hashed_pw = hashed_pw.decode('utf-8')
try:
if not re.match(email_regex, data['email']):
return JsonResponse({'message': 'EMAIL_ERROR'}, status=400)
if len(data['password']) < 8:
return JsonResponse({'message': 'PASSWORD_ERROR'}, status=400)
if signup_data.filter(nickname = data['nickname']).exists():
return JsonResponse({'message': 'UNIQUE_ERROR'}, status=400)
if signup_data.filter(phone_number = data['phone_number']).exists():
return JsonResponse({'message': 'UNIQUE_ERROR'}, status=400)
User.objects.create(
email = data['email'],
password = decoded_hashed_pw,
nickname = data['nickname'],
phone_number = data['phone_number']
)
except KeyError:
return JsonResponse({'message': 'KEY_ERROR'}, status=400)
except IntegrityError:
return JsonResponse({'message': 'UNIQUE_ERROR'}, status=400)
return JsonResponse({'message': 'SUCCESS'}, status=201)
앞서 배운 bcrypt
를 이용하여 암호화하여 회원가입을 하도록 만들겠습니다. email validation
을 할 때 정규식을 사용하여 검증을 하였습니다. 마찬가지로 다른 조건도 정규식을 사용하여 validation을 할 수 있지만 처음 기능 구현을 하여서 이메일만 정규식을 사용하였고 다른식은 조건문을 통해 검증하도록 하였습니다. 물론 이메일도 조건문을 통해 검증을 할 수 있었지만 그렇게 되면 조건이 길어지게 되어 코드가 지저분해진다는 사실을 알았습니다. 처음에는 전부 조건문을 통해 검증을 하였지만 이후 정규식을 활용해보라는 과제가 있었기에 제일 길어졌던 조건문인 이메일에 정규식을 사용하였습니다.
이메일의 조건문이 길어졌던 이유는 @
와 .
의 사용이 필수였고 또한 그 기호의 사용에 있어 순서도 중요했기 때문에 길어졌습니다.
re
는 정규식인 Regular Expression
의 약자인 regex
즉 정규식을 사용할 수 있게 하는 기능을 import 해서 사용해야합니다.
try except
구문으로 여러 에러에 대한 예외처리를 실시하였습니다.
패스워드 암호화는 앞의 bcrypt
포스팅에서 자세하게 다뤘습니다. 그 부분을 참고하여 회원가입 때 암호화를 적용하면 되겠습니다.
Bcrypt 암호화
암호화 과정에서 중요한 부문은 데이터베이스에 암호화된 암호가 들어갈 때 str형태로 저장된다는 것입니다. 그렇기 때문에 encode되어 bytes형식인 암호도 type은 bytes지만 DB에 저장되면 형태는 b$2b$12$dYJ1blTyGOmrCv27nCEPFObqg3A1VOv..TW4z9nfmzChVObjeH9/i
이지만 참고로 제일 앞에 b는 bytes를 나타내는 기호이다. 하지만 python shell 에서 type을 찍어보면 str 형태로 나오기 때문에 나중에 토큰 발행 과정에서 번거로워지지 않으려면 str형태로 decode해서 삽입하는 것이 좋다.
try except 구문에서 중요한 부분은 조건문의 통일이다. 파이썬은 인간친화적인 언어인 만큼 사람이 읽기 쉽게 가독성이 좋아야 파이썬을 제대로 활용하는 것이다. 즉 다른 사람이 어떠한 코드를 보아도 한눈에 알아보기 쉽게 쓰여져야한다는 뜻이다. 그렇기 때문에 try except 구문에서 조건문은 통일성이 있어야한다. 조건문에서 not을 사용하려면 조건에 해당하지 않게 전부 not을 사용하여 조건문에거 거르고 넘어가게 하고 반대의 경우도 통일하여 넘어가게 해야한다. 조건문에서 뒤죽박죽으로 not 조건문과 not이 없는 기본 조건문을 혼용한다면 가독성이 떨어지게 될 것이다.
모든 조건을 잘 구현하였다면 인제 데이터베이스에 httpie
를 이용하여 회원가입 실습을 진행해보자.
user/urls.py
from django.urls import path
from user.views import UserSignUp
urlpatterns = [
path('/signup', UserSignUp.as_view()),
]
우리는 서버 통신을 위한 실습으로 두가지 툴을 사용할 수 있다. httpie
와 postman
이다 우선 httpie는 툴 설치 없이 파이썬 패키지를 이용해 shell에서 사용이 가능하다.
httpie
pip install httpie
postman
포스트맨 사용화면이다. 둘 중 편한것을 사용하면 되겠다.
지금은 httpie
를 이용해 실습해보겠다.
http -v POST localhost:8000/user/signup email="test@naver.com"
nickname="테스트" password= "testpassword123" phone_number= "01011223344"
shell에서 다음과 같은 명령어를 client에서 서버로의 요청을 직접 해볼 수 있다.
서버를 통해 201이 뜨면서 회원가입이 잘된 것을 볼 수 있다. 회원가입에 성공했다면 데이터베이스에도 원하는 정보가 들어가 있어야 할 것이다.
다음과 같이 DB에도 잘 들어가 있다.