[Django] 회원가입 기능 구현하기💡

Inah-_-·2021년 3월 14일
2

Django

목록 보기
3/8
post-thumbnail

instagram NoNo~

🚀 Westagram 회원가입 기능 구현

구현 조건

  • 회원가입 시 사용자 계정(email)을 필수로 한다.
  • 회원가입 시 패스워드를 필수로 한다.
  • 이메일 혹은 패스워드 키가 전달되지 않았을 시 KEY_ERROR를 반환한다.
  • 회원가입 시 이메일의 구성에 @.이 포함되지 않을 시 에러를 반환한다.
  • 회원가입 시 사용자의 정보(email)가 중복되면 에러를 반환한다.
  • 회원가입 성공 시 SUCCESS를 반환한다.
  • [추가 구현 사항] email validation 또는 password validation 과정에서 정규식 사용

1. 프로젝트 생성 및 세팅 ⚙

1️⃣ conda

  	# conda 가상환경 생성 python 버전 지정
    $ conda create -n '가상환경 이름' python=3.8
    
	# conda 가상환경 활성화
	$ conda activate westagram

2️⃣ pip install

    $ pip install django
    $ pip install django-cors-headers
    $ pip install bcrypt
    $ pip install jwt

3️⃣ Django project & app 생성

    $ django-admin startproject westagram
    $ cd westagram

    $ python manage.py startapp user

4️⃣ DB 생성

    $ mysql -u root -p
    
    # mysql database 생성
    mysql> create database westagram character set utf8mb4 collate utf8mb4_general_ci;
    
    $ USE westagram

5️⃣ Settings.py

인증, 관리자모드 관련된 내용 주석 처리 (당장에 사용하지 않음)

INSTALLED_APPS = [
      # 'django.contrib.admin',
      # 'django.contrib.auth',
      'django.contrib.contenttypes',
      'django.contrib.sessions',
      'django.contrib.messages',
      'django.contrib.staticfiles',
  ]

  MIDDLEWARE = [
      'django.middleware.security.SecurityMiddleware',
      'django.contrib.sessions.middleware.SessionMiddleware',
      'django.middleware.common.CommonMiddleware',
      # 'django.middleware.csrf.CsrfViewMiddleware',
      # 'django.contrib.auth.middleware.AuthenticationMiddleware',
      'django.contrib.messages.middleware.MessageMiddleware',
      'django.middleware.clickjacking.XFrameOptionsMiddleware',
  ]

INSTALLED_APPS에 생성한 app, corsheaders 추가

   INSTALLED_APPS = [
      # 'django.contrib.admin',
      # 'django.contrib.auth',
      'django.contrib.contenttypes',
      'django.contrib.sessions',
      'django.contrib.messages',
      'django.contrib.staticfiles',
      'corsheaders'
      'user',
  ]

middleware 추가

    MIDDLEWARE = [
	...
		'corsheaders.middleware.CorsMiddleware',
]

ALLOWED_HOSTS 추가
보통 허용하고자 하는 아이피 주소만 입력하지만, 프로젝트 진행 시 여러 아이피를 허용해야 하기 때문에 *사용

ALLOWED_HOSTS = ['*']

CORS 관련 허용 사항 추가

##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',
)

my_settings.py 생성
settings.py의 SECRET_KEY, DATABASES 잘라오기

SECRET_KEY = 'nw90(46%j&3fq1eyws&dxzoh%0)!d80u1dn@caq-gym27dv#g-'

DATABASES = {
    'default' : {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'westagram',
        'USER': 'root',
        'PASSWORD': '1004',
        'HOST': '127.0.0.1',
        'PORT': '3306',
    }
}

ALGORITHM = 'HS256'

settings.py에 import
SECRET_KEY, DATABASES 변수 지정

from my_settings import SECRET_KEY, DATABASES
SECRET_KEY = SECRET_KEY
DATABASES = DATABASES


2. 회원가입 Models.py 작성해주기 🗒

구현 전에 탐색해보려고 instagram에 들어가봤는데
회원가입 시에 이런 애들이 필요했다.

  • Mobile Number or Email
  • Full Name
  • Username
  • Password

Login 페이지에서 보니
Phone Number or Email or username 중 하나로 로그인할 수 있게끔 되어있었는데
나는 그냥 Email로만 pass하게끔 구현했음
프로젝트 끝나고 다시 와서 모두 구현해야해 미래의 나..화이팅


넘나 깔끔한 나의 models.py 별거 없어서 깔끔해

from django.db import models

class User(models.Model):
    email        = models.EmailField(max_length=100, unique=True, default='')
    password     = models.CharField(max_length=300)

    class Meta:
        db_table = 'users'

email과 password만 입력 받을 거니까 email, password 작성해주고
email은 max_length = 100 (이메일의 최대 길이), 중복되면 안 되니까 unique = True
password는 max_length = 300 해줬는데 왜 이렇게 긴 것이냐?
이따가 views.py 작성할 때 암호화 해줘야 하기 때문~!!~!~
암호화 하게 되면 패스워드가 어어엄청 길어지기 때문에 낙낙~히 300으로 해준 것이다.



3. views.py 작성해주기 🗒

import json, bcrypt, jwt, re

from django.views   import View
from django.http    import JsonResponse, HttpResponse

from .models        import User
from my_settings    import SECRET_KEY, ALGORITHM

작성에 필요한 아이들 import

Python에서 import해온 json, bcrypt, jwt, re
Django에서 import해온 View, JsonResponse
내가 사용하려고 작성한 User class 순으로
블럭끼리 작성해줌, 그래야 코드리뷰 혹은 누군가가 봤을 때
깔끔하고 정리된 느낌을 주어야 읽는 사람이 더 편하게 볼 수 있음
물론 내가 볼때도 편하고 잘 읽힘


구현 조건 작성해주기 ✍

email 혹은 password가 작성되지 않았을 경우

class SignUpView(View):
    def post(self, request):
        try:
            data = json.loads(request.body)

            email        = data['email']
            password     = data['password']
            
        except KeyError:
            return JsonResponse({'message' : 'KEY_ERROR'}, status=400)
         	

내가 헷갈렸던 부분은 만약 user가 필수값을 작성 안했을 시 return Error,
작성 했을 시 return SUCCESS 부분이었는데 아무리 생각해도 코드가 난잡한 것이였따..
처음 views.py에 코드를 작성할 때 ifelif, else가 난무하는 그런 코드였고..

~조건이 맞다면 return SUCCESS해주고 아니면 에러 그것도 아니면 에러 이런 식?

지나가던 동기님의 한마디 "??? : 전부 if랑 else밖에 없네요??"

이때 조금 슬펐따..

왜냐하면 그때 당시 내가 할 수 있는 구현법은 이게 다였으니까 ㅠ
그때가 금요일이였나? 그랬는데 주말에 엄청 구글링 하고 알아봤었음


출처(과거의 나)


근데 email validation을 Django 공식 문서에서 알아보던 도중에
Django_Exceptions을 알게 되었고...

이걸 통해서 elif, else를 사용하지 않고 그냥 KEY_ERROR가 뜨게끔 해줄 수 있었다.

사용자가 회원가입 시 email or password를 작성하지 않았을 경우
KEY_ERROR가 뜨는 코드를 이런식으로 구현했었다면,

if not email or not password:
	return JsonResponse({'message' : 'KEY_ERROR'}, status=400)
else:
	return JsonResponse({'message': 'SUCCESS!'}, status=201)

exceptions, 즉 예외처리를 쓰게 되면 저 식을 써줄 필요 없이
바로 except KeyError를 통해 걸러지게 되는 거다.

Python의 예외처리

try:
    실행 할 코드
except:
    예외 상황이 발생했을 때 실행 할 코드

예외처리를 추가하고 코드가 엄청 간결해지고 보기 쉽게 되었음..
그리고 else SUCCESS는 해줄 필요가 없는게,
어차피 SUCCESS라면 그 다음 코드를 실행하기 때문에
통과하지 못한다면 어떤 식으로든 에러가 난다.

만약 존재하는 email일 경우

if User.objects.filter(email=email).exists():
                return JsonResponse({'message' : 'ALREADY_EXISTS'}, status = 400)

User가 작성한 email을 db에 저장 된 email과 비교 조회하여
같은 email이 있을 경우 'ALREADY_EXISTS' 400에러를 반환한다.


email과 password 정규식

정규식을 사용하기 위해 re를 import한 것!
Django email validator 참고문헌
Django email regex 참고문헌
regex 코드 작성에 도움이 된 글

regex_email    = '^[a-zA-Z0-9+-_.]+@[a-zA-Z0-9_-]+\.[a-zA-Z0-9-.]+$'
regex_password = '\S{8,25}'
if not re.match(regex_email, email):
    return JsonResponse({'message' : 'INVALID_EMAIL'}, status = 400)
if not re.match(regex_password, password):
    return JsonResponse({'message' : 'INVALID_PASSWORD'}, status = 400)

regex_email 이라는 변수를 지정하고 조건을 작성한다.
해석하자면, regex_email은 이 아이들을 포함한다.

regex_emial
(소문자 a~z, 대문자 A~Z, 숫자 0~9, +-_.) + @ + .

re.matchre.match(pattern , string[,flags])
string 시작부분부터 pattern 이 존재하는지 비교하는 정규식 함수로 이름 그대로 매치시킴
re.match말고도 여러 함수가 존재하는데, 자주 사용되는 정규식 함수는 나중에 정리!

regex_password
8자 이상 25자 이하

만약 re.match했을 때 입력받은 값과 정규식으로 지정한 regex_email, regex_password가 일치하지 않으면 'INVALID_EMAIL' 혹은 'INVALID_PASSWORD'를 반환한다.


Password bcrypt

password       = data['password'].encode('utf-8')
password_crypt = bcrypt.hashpw(password, bcrypt.gensalt()).decode('utf-8')

인증&인가
Bcrypt

password = data['password'].encode('utf-8')
해싱 전 입력하는 패스위드를 인코딩해주고~

password_crypt = bcrypt.hashpw(password, bcrypt.gensalt()).decode('utf-8')
입력 받은 값을 해싱 후 decode 해준다.


app urls.py와 project urls.py 작성

app urls.py

from django.urls import path
from .views      import SignUpView

urlpatterns = [
    path('/signup', SignUpView.as_view()),
]

project urls.py

from django.urls import path, include

urlpatterns = [
    path('user', include('user.urls')),
]

마지막, 회원가입 성공!

User.objects.create(email=email, password=password_crypt)
    return JsonResponse({'message': 'SUCCESS!'}, status=201)



SignInView 전 SignUpView까지의 사랑스런 내 코드

profile
Backend Developer

3개의 댓글

comment-user-thumbnail
2022년 7월 18일

포스팅보면서 만들고있는데요.
처음부터 뭔가 잘 안되서 댓글 남깁니다.
가상환경만들고(이름도 일부로 westagram으로 생성)
activate westagram이라고 입력하니
Could not find conda environment: westagram
You can list all discoverable environments with conda info --envs.
이렇게 뜨네요.
어디서 부터 막혔는지 알고자 댓글 남깁니다.

1개의 답글