-
[Django] Django 연습장 - 6. 회원가입 프로세스 개선 (이메일 보내기 & 인증)프로그래밍/Django 2022. 4. 16. 01:48반응형
이번 시간에는 회원가입에 대해서 프로세스를 추가하도록 하겠습니다.
현재 구현해놓은 내용은 이메일을 기반으로 회원가입을 진행합니다.
하지만 지금처럼 가입을 시키면 아무 메일이나, 또는 남의 메일을 입력해서 회원가입을 해버릴 수 있습니다.
따라서 해당 메일이 정말 사용자의 것인지 확인하는 프로세스를 추가하겠습니다.
[작업순서]
1. 회원가입 코드에 메일 전송 코드 추가 & 생성 시 user의 is_active값을 False로 저장할 것임,
2. 메일 전송 코드 작성
3. 메일 전송 내용 중 토큰 생성 함수 작성.
4. 메일 전송에 필요한 html 작성
5. 이메일 인증을 위한 엔드포인트 만들기 (user activate)
6. django smtp서버 정보 연결 (Gmail)
7. 회원가입 해보기
1. 회원가입 코드에 메일 전송 코드 추가
form_valid함수에 메일을 보내는 것을 추가했습니다.
그럼 task_send_register_mail은 어디 있는 함수냐?
app_accounts > task.py라는 파일을 만들고 함수를 생성했습니다.
그리고 app_accounts > forms.py에 UserForm의 save 함수도 지워줍니다. (view단에서 user 생성할 거임)
from django.shortcuts import render, redirect, HttpResponse, get_object_or_404 from django.contrib.sites.shortcuts import get_current_site from django.contrib.auth.hashers import check_password, make_password from django.http import JsonResponse from django.views.generic.edit import FormView,View from django.views.generic import CreateView from django.contrib.auth import authenticate, login, logout from django.urls import reverse_lazy from django.contrib.sites.shortcuts import get_current_site from app_accounts.forms import UserForm, LoginForm from app_accounts.task import task_send_register_mail from app_accounts.models import User .... # 회원가입 class CreateAccounts(FormView): template_name = 'register.html' form_class = UserForm success_url = '/accounts/signin' def form_valid(self, form): password = make_password(form.data.get('password')) user = User( email=form.data.get('email'), password=password, nickname=form.data.get('nickname'), ) user.is_active = False user.save() #회원 가입 이메일 전송송 task_send_register_mail(user, get_current_site(self.request).__str__()) return super().form_valid(form)
2. 메일 전송 코드 작성
해당 작업이 task_send_register_mail 함수를 만드는 작업입니다.
task.py라는 파일을 만들고 함수를 작성합니다.
task.py로 따로 함수를 뺀 이유는 추후에 celery & redis를 적용하여 비동기적으로 email을 보낼 것이기 때문입니다.
from django.template.loader import render_to_string from django.utils.http import urlsafe_base64_encode from django.utils.encoding import force_bytes from django.core.mail import EmailMultiAlternatives from config.settings import DEFAULT_FROM_EMAIL import time from datetime import datetime from app_accounts.models import User from app_accounts.tokens import activate_token from django.conf import settings def task_send_register_mail(user, domain): try: template = 'mail_register.html' now_time = time.mktime(datetime.now().timetuple()) kwargs = { 'uid': urlsafe_base64_encode(force_bytes(user.id)), 'token': activate_token.make_token(user), 'time': int(now_time) } message = render_to_string(template, { 'user': user, 'domain': domain, 'kwargs' : kwargs, }) mail_subject = '회원가입 인증메일' to_email = [user.email] from_email = DEFAULT_FROM_EMAIL body = '' email = EmailMultiAlternatives(mail_subject, body, from_email, to_email) email.attach_alternative(message, "text/html") email.send() except User.DoesNotExist as e: print('email send error')
여기서 또 의문은 activate_token은 뭐지?라는 생각이 드는데 이것이 3번째 작업이다.
3. 메일 전송 내용 중 토큰 생성 함수 작성.
app_accounts > tokens.py 파일을 만들고 함수를 작성합니다.
이곳은 그냥 django에서 auth token을 인증하기 위해 제공하는 기능입니다.
그냥 사용하시면 됩니다.
from django.contrib.auth.tokens import PasswordResetTokenGenerator import six class AccountActivationTokenGenerator(PasswordResetTokenGenerator): def _make_hash_values(self,user, timestamp): return(six.text_type(user.pk) + six.text_type(timestamp) + six.text_type(user.active)) activate_token = AccountActivationTokenGenerator()
4. 메일 전송에 필요한 html 작성
이제 다시 2번 작업에서 작성한 함수를 보면 메일에 필요한 html이 필요하다.
이는 간단하게 다음과 같이 작성하겠습니다.
{% if user.is_active %} <h3>계정이 활성화 되었습니다.</h3> <script language="javascript"> setTimeout(function () { window.close() }, 2000); </script> {% else %} <table border="0" width="671" background=""> <tr> <td align="center" style="padding-bottom: 20px;"> <a target="_blank" href="http://{{ domain }}{% url 'activate' %}?uidb64={{ kwargs.uid }}&token={{ kwargs.token }}&time={{ kwargs.time }}" style="line-height: 50px; font-family: Dotum;color: #fff;font-size: 16px; font-weight: 500; width: 212px;height: 50px; background: #614ED0; display: block; text-decoration: none;">이메일 인증</a> </td> </tr> </table> {% endif %}
다른 건 사실 필요 없고 a태그에서 href에 인증하는 url이 필요합니다.
url_name이 activate인 곳을 찾아가게 됩니다.
요청 방식은 GET이고? 이후에서 query param 형식으로 데이터를 전달합니다.
저것도 app_accounts > views.py에 추가해야 하는 요청인데 일단은 mail부터 잘 가는지 테스트해보겠습니다.
5. 이메일 인증을 위한 엔드포인트 만들기 (user activate) 활성화 로직
app_accounts > views.py
이 부분의 token 체크는 django에서 제공해주는 기능이기 때문에 그냥 사용하면 됩니다.
이메일에서 인증하기 버튼을 누르면 해당 token을 체크하는 이 함수가 동작합니다.
해당 메일에서 제공한 데이터의 대상인 user가 존재하고, token이 올바르면
해당 user의 계정을 활성화시키는 로직입니다.
def activate(request): uidb64 = request.GET.get('uidb64') token = request.GET.get('token') uid = force_text(urlsafe_base64_decode(uidb64)) user = get_object_or_404(User, pk=uid) user = User.objects.get(pk=uid) #활성화 인증 if user is not None and activate_token.check_token(user, token): user.is_active = True user.save() return redirect('signin_page') else: return HttpResponse('비정상적인 접근입니다.')
* 현재 urls.py
urlpatterns = [ path('', index, name='accounts_main'), path('signup', CreateAccounts.as_view(), name='register'), path('signin', LoginPage.as_view(), name='signin_page'), path('login', LoginView.as_view(), name='login'), path('logout', LogOutView.as_view(), name='logout'), path('activate', activate, name='activate') ]
6. django smtp서버 정보 연결 (Gmail)
조금 귀찮기는 한데. 한 번 설정하면 편합니다.
대신 정보가 잘못 나가면 골치 아파지기 때문에. secret.json에 데이터를 넣는 게 좋습니다.
사용하는데 한계가 있으므로 개발 서버에서만 사용하고 실제 서비스를 할 때는
AWS SES 서비스 같은 것을 사용하는 게 편합니다.
google 메일에 들어가서 2가지 설정을 완료하고 다음의 내용을 넣어주면 됩니다.
설정 페이지
https://support.google.com/mail/answer/7126229?hl=ko&rd=3&visit_id=1-636281811566888160-3239280507#ts=1665018을 참고하면 좋습니다.1.IMAP 사용
- 일단 Gmail에서 설정을 들어간다.
- 전달 및 POP/IMAP 설정을 들어간다.
- IMAP 사용을 누르고 저장한다.
2. 보안 수준 낮은 앱 허용
[참고]
config > settings.py 설정
하단에 smtp서버 정보를 넣어준다.
#Email EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' EMAIL_USE_TLS = True EMAIL_PORT = 587 DEFAULT_FROM_EMAIL = get_secret("DEFAULT_FROM_EMAIL") EMAIL_HOST = get_secret('EMAIL_HOST') EMAIL_HOST_USER = get_secret('EMAIL_HOST_USER') EMAIL_HOST_PASSWORD = get_secret('EMAIL_HOST_PASSWORD')
Email host는
- smtp.gmail.com로 작성하고
- Host_user와 default_from_email은 본인의 구글 mail,
- password는 google계정 앱 패스워드를 입력하면 됩니다.
[참고] google계정 App password 설정
http://support.google.com/accounts/bin/answer.py?answer=185833
7. 테스트...
회원가입해보기!
1. 회원가입 시 is_active 값은 False여야 합니다..
2. 회원 가입하면 해당 메일로 인증 메일이 발송되어야 합니다.
3. 버튼 누른 후 is_active값의 변화
is_active값이 성공적으로 true로 변하였습니다.
이번 시간은 내용이 길어서 설명이 부족할 수 있는데.
코드는 git에 업로드할 것이니 참고하시면 되고
추가적으로 SMTP 서버 설정에 대한 내용은 굳이 google이 아니어도 상관이 없으므로 편하신 SMTP 서버를 가져와서 세팅한 후 사용하시면 됩니다.
반응형'프로그래밍 > Django' 카테고리의 다른 글
[Django] Django 연습장 - 7. 이메일 전송 비동기 방식 (celery + redis) (0) 2022.04.17 [Django] Django 연습장 - 5. html씌우기 (0) 2022.04.15 [Django] Django 연습장 - 4. 로그인 기능 만들기 (0) 2022.04.15 [Django] Django 연습장 - 3. User form 수정해서 회원 가입 조건 변경 (0) 2022.04.14 [Django] Django 연습장 - 2. User만들기 (1) 2022.04.14