dj_rest_auth 이메일 관련 흐름 및 시행착오

오정배·2023년 12월 19일
0

django

목록 보기
2/2

※ 프로젝트를 진행하며 dj_rest_auth의 이메일 인증 방식을 사용해보았으며, 해당 작업을 하면서 이해가 잘 안되서 글로 정리하면서 한번더 복습을 해보려 합니다.

dj_rest_auth.registration의 기본 설정이 다 되었다는 가정하에 진행하였습니다.
(views, urls, settings 등...)

이메일 인증 관련 설정

# settings.py
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_PORT = 587
EMAIL_HOST_USER = env('EMAIL_HOST_USER') # 가입 인증 메일을 보낼 이메일
EMAIL_HOST_PASSWORD = env('EMAIL_HOST_PASSWORD') # 비밀번호(구글에서 앱 비밀번호 발급 필요)
EMAIL_USE_TLS = True
DEFAULT_FROM_EMAIL = EMAIL_HOST_USER
ACCOUNT_CONFIRM_EMAIL_ON_GET = True
ACCOUNT_EMAIL_REQUIRED = True
ACCOUNT_EMAIL_VERIFICATION = 'mandatory'
EMAIL_CONFIRMATION_AUTHENTICATED_REDIRECT_URL = '/'
ACCOUNT_EMAIL_CONFIRMATION_EXPIRE_DAYS = 1
ACCOUNT_EMAIL_SUBJECT_PREFIX = '인증 메일 제목앞에 붙일 접두사'
  1. EMAIL_BACKEND

    • 이메일을 발송할 때 사용되는 백엔드를 설정합니다.
      여기서는 SMTP 백엔드를 사용하며, django.core.mail.backends.smtp.EmailBackend을 지정하여 설정
  2. EMAIL_HOST, EMAIL_PORT, EMAIL_HOST_USER, EMAIL_HOST_PASSWORD, DEFAULT_FROM_EMAIL

    • SMTP 서버의 연결 설정입니다.
      Gmail을 사용하고 있으며, 해당 Gmail 계정으로 이메일을 발송하기 위해 필요한 SMTP 서버 및 계정 정보를 설정
  3. ACCOUNT_CONFIRM_EMAIL_ON_GET

    • 사용자가 회원가입 시 이메일 주소를 확인하도록 하는 옵션입니다.
      이 설정이 True이면, 사용자가 회원가입 폼을 제출할 때 이메일 확인 링크를 받을 수 있습니다.
  4. ACCOUNT_EMAIL_REQUIRED

    • 사용자가 회원가입 시 이메일 주소를 필수로 입력해야 하는지 여부를 설정합니다.
      True로 설정하면, 사용자는 반드시 이메일 주소를 입력해야 합니다.
  5. ACCOUNT_EMAIL_VERIFICATION

    • 이메일 주소의 확인 방법을 설정합니다.
      'mandatory'로 설정하면, 사용자가 이메일 주소를 입력한 후 반드시 이메일 확인을 거쳐야 합니다.
  6. EMAIL_CONFIRMATION_AUTHENTICATED_REDIRECT_URL

    • 사용자가 이메일 주소를 확인한 경우, 리다이렉트할 URL을 지정합니다.
  7. ACCOUNT_EMAIL_CONFIRMATION_EXPIRE_DAYS

    • 이메일 확인 키의 만료 기간을 설정합니다.

이메일 전송 및 인증 시 필요한 url 설정

# accounts앱/urls.py
from .views import ConfirmEmailView
from dj_rest_auth.registration.views import VerifyEmailView

urlpatterns = [
    ...기타 url...
    re_path(r'^account-confirm-email/$', VerifyEmailView.as_view(), name='account_email_verification_sent'),
    re_path(r'^account-confirm-email/(?P<key>[-:\w]+)/$', ConfirmEmailView.as_view(), name='account_confirm_email'),
]
  • account-confirm-email/로 접속하여 이메일 확인 메시지를 전송
  • 사용자가 이메일에서 제공된 링크(account-confirm-email/<key>/)를 클릭하여 이메일 주소를 확인

이메일 인증 관련 view 설정

from allauth.account.models import EmailConfirmation, EmailConfirmationHMAC
from django.http import HttpResponseRedirect
from rest_framework.views import APIView
from rest_framework.permissions import AllowAny

class ConfirmEmailView(APIView):
    permission_classes = [AllowAny]

    def get(self, *args, **kwargs):
        self.object = confirmation = self.get_object()
        confirmation.confirm(self.request)
        return HttpResponseRedirect('/login/success/') # 인증성공

    def get_object(self, queryset=None):
        key = self.kwargs['key']
        email_confirmation = EmailConfirmationHMAC.from_key(key)
        if not email_confirmation:
            if queryset is None:
                queryset = self.get_queryset()
            try:
                email_confirmation = queryset.get(key=key.lower())
            except EmailConfirmation.DoesNotExist:
                return HttpResponseRedirect('/login/failure') # 인증실패
        return email_confirmation

    def get_queryset(self):
        qs = EmailConfirmation.objects.all_valid()
        qs = qs.select_related("email_address__user")
        return qs

def get() - HTTP GET 요청을 처리
get_object 메소드를 통해 확인 객체를 얻습니다.
• 확인 객체의 confirm 메소드를 호출하여 이메일 주소를 확인합니다.
• 이메일 주소가 성공적으로 확인되면 /login/success/로 리다이렉트합니다.
• 확인이 실패하면 /login/failure로 리다이렉트합니다

def get_object()
• URL에서 전달된 키(key)를 사용하여 이메일 확인 객체(EmailConfirmationHMAC)를 가져오는 역할을 합니다.
• 만약 해당 키로 EmailConfirmationHMAC 객체를 가져오지 못하면, 기본적인 EmailConfirmation 모델을 사용하여 키와 일치하는 객체를 조회합니다.
• 만약 이메일 확인 객체가 존재하지 않으면 /login/failure로 리다이렉트합니다.

def get_queryset()
EmailConfirmation 모델에서 모든 유효한 객체를 가져오는데, 이때 all_valid 메소드를 사용합니다.
select_related를 사용하여 관련된 이메일 주소의 사용자 정보를 함께 조회하도록 설정합니다.

인증 메일 템플릿 설정

  • 템플릿 위치 설정

    # settings.py
    TEMPLATES = [
        {
            "BACKEND": "django.template.backends.django.DjangoTemplates",
            "DIRS": [BASE_DIR, 'templates'],
            "APP_DIRS": True,
            "OPTIONS": {
                "context_processors": [
                    "django.template.context_processors.debug",
                    "django.template.context_processors.request",
                    "django.contrib.auth.context_processors.auth",
                    "django.contrib.messages.context_processors.messages",
                ],
            },
        },
    ]
  • manage.py와 같은 디렉토리에 templates/account/email 폴더 생성
    email_confirmation_signup_message.html 작성 - 이메일의 메인 컨텐츠가 되겠습니다.

    <!-- email_confirmation_signup_message.html -->
    {% load account %}
    {% load i18n %}
    
    {% block content %}
    {% autoescape off %}
    {% user_display user as user_display %}
    {% blocktrans with site_name=current_site.name site_domain=current_site.domain %}
    
    <!DOCTYPE html>
    <html lang="ko-KR">
        <head>
            <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
            <meta name="viewport" content="width=device-width, initial-scale=1">
            <meta http-equiv="X-UA-Compatible" content="IE=edge" />
            <title></title>
        </head>
        <body>
        <div>
            <div>
                <h1>안녕하세요, ~~~입니다</h1>
                <p>아래 버튼을 눌러 계정을 인증하고, 로그인해주세요!</p>
                <p>귀하의 아이디는 <span style="font-weight: bold;">{{ user_display }}</span>입니다.</p>
                <div>
                    <a href="{{ activate_url }}">계정 인증하기</a>
                </div>
                <p>만약 동작하지 않는다면 다음 링크를 복사해 브라우저에 붙여넣기해주세요</p>
                <p>{{ activate_url }}</p>
                <p>문의사항이 있다면 이메일 주소로 보내주세요</p>
            </div>
        </div>
    
        </body>
    </html>
    
    {% endblocktrans %}
    {% endautoescape %}
    {% endblock %}

    email_confirmation_subject.txt 작성 - 이메일의 제목이 되겠습니다.

<!--email_confirmation_subject.txt-->
{프로젝트명}에 오신 것을 환영합니다!


이슈사항

인증메일 재발송 시 템플릿 적용이 되지 않음

  • 회원가입 정보 입력 후 이메일 인증 요청시에는 템플릿이 적용되나, 인증 메일 재발송 요청시 템플릿 적용이 안되는 문제가 있었음.

왜?

  • 회원가입 시 사용되는 템플릿 파일의 이름과 단순 인증 시 사용되는 템플릿 파일의 이름이 다르기 때문.
    Sending Email — django-allauth 0.59.0 documentation
  • 공식 문서에 따르면 아래와 같다.
    회원가입 시 사용하는 템플릿 명
    account/email/email_confirmation_signup_message.html
    인증 시 사용하는 템플릿 명
    account/email/email_confirmation_message.html
  • 회원가입 시에 사용하는 템플릿 이름과 인증 시 사용하는 템플릿 명이 다르며, 재발송은 인증에 해당하여 새로운 파일을 만들어야 적용이 되었다.

[참고] https://velog.io/@kjyeon1101/Django-%EC%9D%B4%EB%A9%94%EC%9D%BC-%EC%9D%B8%EC%A6%9D%ED%95%98%EA%B8%B0-%EC%9D%B4%EB%A9%94%EC%9D%BC-%ED%85%9C%ED%94%8C%EB%A6%BF

profile
개발 관련 블로그 입문

0개의 댓글

관련 채용 정보