[To do list] Django Custom User + 이메일 인증 시스템 구현 가이드 1/2

2025. 5. 13. 22:55·과제

🔐 Django Custom User + 이메일 인증 시스템 구현 가이드

📌 목표

  1. AbstractBaseUser 또는 AbstractUser + PermissionsMixin을 이해하고 커스텀 유저 구현하기
  2. Manager 클래스의 개념을 이해하고 커스텀 유저 매니저 구현하기
  3. CBV (Class-Based View) 방식으로 회원가입, 로그인, 로그아웃 구현하기
  4. django.core.signing을 이용한 이메일 인증 흐름 이해 및 구현
  5. send_mail 기능을 활용한 SMTP 기반 이메일 전송 구현
  6. 환경변수를 통한 민감 정보 보호 및 설정 적용하기

✅ 요구사항 요약

  • CBV 기반으로 회원가입/로그인/이메일 인증 구현
  • AbstractBaseUser 기반 CustomUser + Manager 구현
  • signing + send_mail 활용한 인증메일 발송 기능 구현

1️⃣ 환경변수 설정 (.secret_config/secret.json)

민감 정보(SECRET_KEY, SMTP 정보)는 외부 파일로 관리하여 보안을 확보합니다.

secret.json 예시:

{
  "DJANGO_SECRET_KEY": "your_secret",
  "EMAIL": {
    "HOST_USER": "your_email@example.com",
    "PASSWORD": "your_email_password"
  }
}
  • secret.json은 .secret_config 폴더에 위치시킵니다.
  • settings.py에서 json.load()로 불러와 사용합니다.

2️⃣ models.py: Custom User & Manager

from django.contrib.auth.base_user import AbstractBaseUser, BaseUserManager
from django.contrib.auth.models import PermissionsMixin

class UserManager(BaseUserManager):
    def create_user(self, email, password=None):
        if not email:
            raise ValueError('이메일 필수')
        user = self.model(email=self.normalize_email(email))
        user.set_password(password)
        user.is_active = False
        user.save(using=self._db)
        return user

    def create_superuser(self, email, password):
        user = self.create_user(email, password)
        user.is_admin = True
        user.is_active = True
        user.save(using=self._db)
        return user

class User(AbstractBaseUser, PermissionsMixin):
    email = models.EmailField(unique=True)
    nickname = models.CharField(max_length=20, unique=True)
    is_active = models.BooleanField(default=False)
    is_admin = models.BooleanField(default=False)

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = []

    objects = UserManager()

    @property
    def is_staff(self):
        return self.is_admin

3️⃣ forms.py: 회원가입 & 로그인 폼

from django.contrib.auth.forms import UserCreationForm, AuthenticationForm

class SignupForm(UserCreationForm):
    class Meta:
        model = User
        fields = ('email', 'nickname')
        widgets = {
            'email': forms.EmailInput(attrs={'class': 'form-control'}),
            'nickname': forms.TextInput(attrs={'class': 'form-control'})
        }

class LoginForm(AuthenticationForm):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['username'].widget.attrs.update({'class': 'form-control'})
        self.fields['password'].widget.attrs.update({'class': 'form-control'})

4️⃣ cb_views.py: CBV 방식 회원가입/로그인/인증

📩 SignupView (이메일 인증 포함)

class SignupView(FormView):
    template_name = 'auth/signup.html'
    form_class = SignupForm

    def form_valid(self, form):
        user = form.save(commit=False)
        user.nickname = form.cleaned_data['nickname']
        user.save()

        signer = TimestampSigner()
        signed_email = signer.sign(user.email)
        dump = signing.dumps(signed_email)

        url = f"{self.request.scheme}://{self.request.META['HTTP_HOST']}/verify/?code={dump}"

        subject = '[Pystagram] 이메일 인증을 완료해주세요'
        message = f'다음 링크를 클릭해주세요: <a href="{url}">이메일 인증</a>'

        send_email(subject, message, user.email)

        return render(self.request, 'auth/signup_done.html', {'user': user})

🔐 verify_email

def verify_email(request):
    code = request.GET.get('code', '')
    signer = TimestampSigner()
    try:
        decoded = signing.loads(code)
        email = signer.unsign(decoded, max_age=1800)
    except (TypeError, SignatureExpired):
        return render(request, 'auth/verify_failed.html')

    user = get_object_or_404(User, email=email, is_active=False)
    user.is_active = True
    user.save()
    return render(request, 'auth/verify_success.html')

🔓 LoginView

class LoginView(FormView):
    template_name = 'auth/login.html'
    form_class = LoginForm
    success_url = reverse_lazy('todo_list')

    def form_valid(self, form):
        user = form.get_user()
        login(self.request, user)

        next_page = self.request.GET.get('next')
        if next_page:
            return HttpResponseRedirect(next_page)
        return super().form_valid(form)

5️⃣ urls.py 설정

# users/urls.py
urlpatterns = [
    path('signup/', SignupView.as_view(), name='signup'),
    path('login/', LoginView.as_view(), name='login'),
    path('logout/', LogoutView.as_view(), name='logout'),
    path('verify/', verify_email, name='verify_email'),
]

# config/urls.py
urlpatterns = [
    path('users/', include('users.urls')),
]

6️⃣ templates 구조

📁 templates/
├─ base.html
├─ auth/
    ├─ signup.html
    ├─ signup_done.html
    ├─ login.html
    ├─ verify_success.html
    └─ verify_failed.html
  • 모든 템플릿은 base.html을 extend 하도록 설정
  • verify_success.html: 이메일 인증 성공 시 메시지 + 리다이렉트 JS
  • verify_failed.html: 링크 오류/만료 시 메시지 출력

✅ 이 구조를 통해 실무에서도 적용 가능한 유저 인증 시스템을 구현할 수 있습니다!

'과제' 카테고리의 다른 글

[To do list] Django Custom User + 이메일 인증 시스템 구현 가이드 2/2  (0) 2025.05.13
📌 Django Todo 프로젝트: 이미지 업로드 + 썸네일 생성 + Summernote 적용 전체 흐름 정리  (0) 2025.05.12
📝 Django Todo 프로젝트: 이미지 처리 + Summernote + Bootstrap5 통합 실습 정리  (0) 2025.05.12
📚 Django 프로젝트 시작하기 - 가상환경 구축부터 서버 실행까지  (0) 2025.04.30
Flask practice blog 구축 인터페이스(UI) posts.html (3/3)  (0) 2025.04.22
'과제' 카테고리의 다른 글
  • [To do list] Django Custom User + 이메일 인증 시스템 구현 가이드 2/2
  • 📌 Django Todo 프로젝트: 이미지 업로드 + 썸네일 생성 + Summernote 적용 전체 흐름 정리
  • 📝 Django Todo 프로젝트: 이미지 처리 + Summernote + Bootstrap5 통합 실습 정리
  • 📚 Django 프로젝트 시작하기 - 가상환경 구축부터 서버 실행까지
Chansman
Chansman
안녕하세요! 코딩을 시작한 지 얼마 되지 않은 초보 개발자 찬스맨입니다. 이 블로그는 제 학습 기록을 남기고, 다양한 코딩 실습을 통해 성장하는 과정을 공유하려고 합니다. 초보자의 눈높이에 맞춘 실습과 팁, 그리고 개발하면서 겪은 어려움과 해결 과정을 솔직하게 풀어내려 합니다. 함께 성장하는 개발자 커뮤니티가 되기를 바랍니다.
  • Chansman
    찬스맨의 프로그래밍 스토리
    Chansman
  • 전체
    오늘
    어제
    • 분류 전체보기 (787)
      • Python (32)
      • 프로젝트 (110)
      • 과제 (25)
      • Database (40)
      • 멘토링 (11)
      • 특강 (37)
      • 기술블로그 (41)
      • 기술블로그-Fastapi편 (33)
      • 기술블로그-Django편 (153)
      • 기술블로그-Flask편 (36)
      • AI 분석 (5)
      • HTML & CSS (31)
      • JavaScript (17)
      • AWS_Cloud (21)
      • 웹스크래핑과 데이터 수집 (14)
      • Flask (42)
      • Django (77)
      • Fastapi (16)
      • 연예 (14)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    life reflection
    btsdischarge
    RM
    chatgpterror
    livebroadcast
    뷔
    global politics
    chinanightlife
    americanlaw
    smartphonedurability
    bts
    classaction
    btsjungkook
    basalcellcarcinoma
    lawsuitculture
    self-growth
    titaniumcase
    urbantrends
    trumpmuskclash
    btsreunion
    gpterror
    youngprofessionals
    hotcoffeecase
    americaparty
    homebartrend
    btscomeback
    remittance
    travel ban
    college reunions
    newpoliticalparty
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
Chansman
[To do list] Django Custom User + 이메일 인증 시스템 구현 가이드 1/2
상단으로

티스토리툴바