훈훈훈
파이썬(Django) :: 회원가입 시 이메일 인증 API 본문
이번 포스팅은 장고(Django)로 회원가입 시 인증 이메일을 보내는 API Code를 정리 해보려고한다.
회원가입 API 기반으로 작성하기 때문에 회원가입/로그인에 관한 자세한 내용은 아래 링크를 참고 바란다.
https://wave1994.tistory.com/65?category=872868
API 구현하기에 앞서 Gmail SMTP(Simple Mail Transfer Protocol)을 사용하기 위해 아래와 같은 설정을 하였다.
# 사전 설정
1. IMAP 설정
- 이메일 클라이언트에서 Gmail을 사용할 수 있게 IMAP 설정을 1단게로 설정한다.
2. 보안 수준 설정
- 보안 수준 설정을 통해 Gmail에서 자체 차단 없이 이메일을 발송할 수 있다.
https://support.google.com/accounts/answer/6010255
# 코드 구현
모든 설정을 끝마쳤다면, 이제 Django에서 SMTP 설정을 하자,
다른 블로그들을 둘러보았을떄 대부분 settings.py에서 설정을 하였지만, 해당 파일은 Git에 올라갈 수 있기 때문에 정보가 외부로 노출될 수 있다. 따라서 my_settings.py 파일을 새로 생성하여 해당 파일에 Json 형식으로 아래와 같이 작성하도록한다.
추가적으로 SECRET_KEY와 데이터 베이스도 외부로 노출되면 안되는 정보이기 때문에 아래와 같이 작성한다.
DATABASES = {
'default' : {
'ENGINE' : 'django.db.backends.mysql',
'NAME' : 'Scheme Name',
'USER' : 'User Name',
'PASSWORD': 'Your Password',
'HOST' : 'localhost',
'PORT' : 'Database Server Port',
'OPTIONS': {
'init_command': "SET sql_mode='STRICT_TRANS_TABLES'",
'charset' : 'utf8mb4',
'use_unicode' : True,
},
}
}
SECRET_KEY = {
'secret' :'m!#@+v40p*05jd2fds2fe)me1f&4mvfi!igbv7b^2dyrn5=o2dw!i-0u7*&^',
'algorithm':'HS256'
}
EMAIL = {
'EMAIL_BACKEND' :'django.core.mail.backends.smtp.EmailBackend',
'EMAIL_USE_TLS' : True,
'EMAIL_PORT' : 587,
'EMAIL_HOST' : 'smtp.gmail.com',
'EMAIL_HOST_USER' : 'Gmail ID@gmail.com',
'EMAIL_HOST_PASSWORD': 'Gmail Password',
'SERVER_EMAIL' : 'Gmail ID',
'REDIRECT_PAGE' : 'https://wave1994.tistory.com'
}
그 다음 settings로 가서 아래와 코드를 추가한다.
import my_settings
SECRET_KEY = my_settings.SECRET_KEY
DATABASES = my_settings.DATABASES
EMAIL_BACKEND = my_settings.EMAIL['EMAIL_BACKEND']
EMAIL_USE_TLS = my_settings.EMAIL['EMAIL_USE_TLS']
EMAIL_PORT = my_settings.EMAIL['EMAIL_PORT']
EMAIL_HOST = my_settings.EMAIL['EMAIL_HOST']
EMAIL_HOST_USER = my_settings.EMAIL['EMAIL_HOST_USER']
EMAIL_HOST_PASSWORD = my_settings.EMAIL['EMAIL_HOST_PASSWORD']
SERVER_EMAIL = my_settings.EMAIL['SERVER_EMAIL']
이제 토큰을 생성하는 함수를 작성하자.
해당 코드는 token.py 파일을 생성하여 작성하였다.
import six
from django.contrib.auth.tokens import PasswordResetTokenGenerator
class AccountActivationTokenGenerator(PasswordResetTokenGenerator):
def _make_hash_value(self, user, timestamp):
return (six.text_type(user.pk) + six.text_type(timestamp)) + six.text_type(user.is_active)
account_activation_token = AccountActivationTokenGenerator()
그 다음 이메일 발송 시 보내지는 Text를 작성하는 함수를 작성하자.
해당 코드는 text.py 파일을 생성하여 작성하였다.
def message(domain, uidb64, token):
return f"아래 링크를 클릭하면 회원가입 인증이 완료됩니다.\n\n회원가입 링크 : http://{domain}/account/activate/{uidb64}/{token}\n\n감사합니다."
위 코드에서 회원가입 링크는 Active를 담당하는 엔드포인트 URL 주소이다.
해당 엔드포인트는 아래에서 추가적으로 설명하려고한다.
이제 회원가입 시 바로 이메일을 발송하는 API를 작성하자.
먼저 회원가입 관련 앱은 Account 앱을 설치한다.
그다음 앱의 경로에 있는 models.py에 아래와 같이 작성한다.
from django.db import models
class Account(models.Model):
name = models.CharField(max_length=50, null=True)
password = models.CharField(max_length=400)
email = models.EmailField(max_length=200)
is_active = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
db_table = 'accounts'
project 디렉터리에 있는 urls.py와 account App 경로에 있는 urls.py에 아래와 같이 각각 추가한다.
'''
Project 경로에 있는 urls.py
'''
from django.urls import path, include
urlpatterns = [
path('account', include('account.urls')),
]
'''
account/urls.py
'''
from django.urls import path
from .views import SignUpView , SignInView, Activate
urlpatterns = [
path('/signup', SignUpView.as_view()),
path('/signin', SignInView.as_view()),
path('/activate/<str:uidb64>/<str:token>', Activate.as_view())
]
이제 View 파일을 작성하겠다.
먼저 account/view.py에서 아래 모듈을 임포트한다.
import jwt
import json
from .models import Account
from .tokens import account_activation_token
from .text import message
from my_settings import SECRET_KEY, EMAIL
from django.views import View
from django.http import HttpResponse, JsonResponse
from django.core.exceptions import ValidationError
from django.core.validators import validate_email
from django.shortcuts import redirect
from django.contrib.sites.shortcuts import get_current_site
from django.utils.http import urlsafe_base64_encode,urlsafe_base64_decode
from django.core.mail import EmailMessage
from django.utils.encoding import force_bytes, force_text
그 다음 회원가입에 관한 SignUpView 클래스를 생성하였다.
class SignUpView(View):
def post(self, request):
data = json.loads(request.body)
try:
validate_email(data["email"])
if Account.objects.filter(email=data["email"]).exists():
return JsonResponse({"message" : "EXISTS_EMAIL"}, status=400)
user = Account.objects.create(
email = data["email"],
password = bcrypt.hashpw(data["password"].encode("UTF-8"), bcrypt.gensalt()).decode("UTF-8"),
is_active = False
)
current_site = get_current_site(request)
domain = current_site.domain
uidb64 = urlsafe_base64_encode(force_bytes(user.pk))
token = account_activation_token.make_token(user)
message_data = message(domain, uidb64, token)
mail_title = "이메일 인증을 완료해주세요"
mail_to = data['email']
email = EmailMessage(mail_title, message_data, to=[mail_to])
email.send()
return JsonResponse({"message" : "SUCCESS"}, status=200)
except KeyError:
return JsonResponse({"message" : "INVALID_KEY"}, status=400)
except TypeError:
return JsonResponse({"message" : "INVALID_TYPE"}, status=400)
except ValidationError:
return JsonResponse({"message" : "VALIDATION_ERROR"}, status=400)
마지막으로 인증을 담당하는 클래스인 Activate를 작성하였다.
class Activate(View):
def get(self, request, uidb64, token):
try:
uid = force_text(urlsafe_base64_decode(uidb64))
user = Account.objects.get(pk=uid)
if account_activation_token.check_token(user, token):
user.is_active = True
user.save()
return redirect(EMAIL['REDIRECT_PAGE'])
return JsonResponse({"message" : "AUTH FAIL"}, status=400)
except ValidationError:
return JsonResponse({"message" : "TYPE_ERROR"}, status=400)
except KeyError:
return JsonResponse({"message" : "INVALID_KEY"}, status=400)
# 실행 결과
mac OS 환경에서 httpie를 이용하여 아래와 같이 테스를 진행하였다.
회원가입 엔드포인트로 이메일과 패스워드를 입력 시 가입이 완료되며, 아래와 같이 회원 가입 인증 메일이 발송된 것을 확인할 수 있다.
** 추가적으로 EC2 사용 시 계정에 접근하는 IP가 변경되어 구글에서 차단하는 현상이 발생했다. 해당 현상 발생 시 아래 링크 참고 바란다.
https://support.google.com/mail/forum/AAAAK7un8RUEbelsGrXe68/?hl=en-GB
'파이썬 > Django' 카테고리의 다른 글
파이썬(Django) :: Select_related 와 Prefetch_related (0) | 2020.04.13 |
---|---|
파이썬(Django) :: 회원가입 시 입력 값 검증 함수 (0) | 2020.03.21 |
파이썬(Django) :: 데이터베이스에 csv파일 삽입하기 (0) | 2020.03.07 |
파이썬(Django) :: migrations 파일 정리 CLI Command (0) | 2020.02.29 |
파이썬(Django) :: 장고에 mysql 데이터 베이스 연동하기 (0) | 2020.02.17 |