Chapter 8-6 Mini Project: Django Login & Logout 기능 만들기

2025. 5. 12. 20:19·Django
목차
  1. 🔥 Mini Project: Django Login & Logout 기능 만들기
  2. ✅ 핵심 개념 정리
  3. ✅ 로그인 폼 정의하기 (LoginForm)
  4. ✅ 로그인 뷰 작성
  5. ✅ URL 연결
  6. ✅ 로그인 템플릿 (login.html)
  7. 🔐 보안 팁
  8. 📌 마무리 체크리스트

🔥 Mini Project: Django Login & Logout 기능 만들기

이번 포스트에서는 Django에서 로그인과 로그아웃 기능을 구현하는 방법을 정리합니다. 인증 로직의 핵심은 Django 내장 함수인 authenticate와 사용자 정의 LoginForm을 활용하는 것입니다.


✅ 핵심 개념 정리

용어 설명

authenticate() 이메일과 비밀번호로 사용자 인증 시도. 성공 시 User 객체 반환, 실패 시 None
login() 인증된 사용자를 세션에 등록해 로그인 상태로 만듦
logout() 현재 로그인된 사용자 세션 삭제
LoginForm 사용자로부터 이메일과 패스워드를 입력받고 인증하는 커스텀 폼

✅ 로그인 폼 정의하기 (LoginForm)

# member/forms.py
from django import forms
from django.contrib.auth import authenticate

class LoginForm(forms.Form):
    email = forms.CharField(
        label='이메일',
        required=True,
        widget=forms.EmailInput(attrs={
            'placeholder': 'example@example.com',
            'class': 'form-control'
        })
    )
    password = forms.CharField(
        label='패스워드',
        required=True,
        widget=forms.PasswordInput(attrs={
            'placeholder': 'password',
            'class': 'form-control'
        })
    )

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.user = None

    def clean(self):
        cleaned_data = super().clean()
        email = cleaned_data.get('email')
        password = cleaned_data.get('password')
        self.user = authenticate(email=email, password=password)

        if self.user is None:
            raise forms.ValidationError('이메일 또는 비밀번호가 올바르지 않습니다.')
        if not self.user.is_active:
            raise forms.ValidationError('유저가 인증되지 않았습니다.')

        return cleaned_data

✅ 로그인 뷰 작성

from django.contrib.auth import get_user_model, login
from django.core import signing
from django.core.signing import TimestampSigner, SignatureExpired
from django.http import HttpResponseRedirect
from django.shortcuts import render, get_object_or_404
from django.views.generic import FormView
from django.urls import reverse_lazy
from django.shortcuts import render

from member.forms import SignupForm, LoginForm
from utils.email import send_email

User = get_user_model()

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

    def form_valid(self, form):
        user = form.save()
        
        # 이메일 발송
        signer = TimestampSigner()
        signed_user_email = signer.sign(user.email)
        signer_dump = signing.dumps(signed_user_email)
        # print(signer_dump)
        #
        # decoded_user_email = signing.loads(signer_dump)
        # print(decoded_user_email)
        # email = signer.unsign(decoded_user_email, max_age=60 * 30)
        # print(email)

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

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

        send_email(subject, message, user.email)

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


def verify_email(request):
    code = request.GET.get('code', '')

    signer = TimestampSigner()
    try:
        decoded_user_email = signing.loads(code)
        email = signer.unsign(decoded_user_email, max_age=60 * 30)
    except (TypeError, SignatureExpired):
        return render(request, template_name='auth/not_verified.html')

    user = get_object_or_404(User, email=email, is_active=False)
    user.is_active = True
    user.save()

    # return redirect(reverse('login'))
    return render(request, template_name='auth/email_verified_done.html', context={'user': user})

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

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

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

        return HttpResponseRedirect(self.get_success_url())

 


✅ URL 연결

# config/urls.py
from django.urls import path
from member.views import LoginView, LogoutView

urlpatterns = [
    path('login/', LoginView.as_view(), name='login'),
    path('logout/', LogoutView.as_view(), name='logout'),
]

✅ 로그인 템플릿 (login.html)

<!-- templates/auth/login.html -->
{% extends 'base.html' %}
{% block content %}
    <h1 class="title">로그인</h1>
    <form method="POST">
      {% csrf_token %}
      {% include 'include/form.html' %}
    <button class="btn btn-primary">로그인</button>
    </form>
{% endblock %}

signup.html

<!-- templates/auth/signup.html -->
{% extends 'base.html' %}
{% block content %}
  <div>
    <h1 class="title">회원가입</h1>
    <form method="POST">
      {% csrf_token %}
      {% include 'include/form.html' %}
      <button class="btn btn-primary">회원가입</button>
    </form>
  </div>
{% endblock %}

templates/include/form.html

    {% for field in form %}
        <div class="form-group row mb-2">
          <label class="form-label col-md-2" for="{{ field.auto_id }}">{{ field.label }}</label>
          <div class="col-md-10">
            {{ field }}
          </div>
          {% for error in field.errors %}
            <span class="text-danger">{{ error }}</span>
          {% endfor %}
        </div>
      {% endfor %}
      {% for error in form.non_field_errors %}
        <p class="text-danger">{{ error }}</p>
    {% endfor %}

base.html 버튼 추가 

<!-- templates/base.html -->
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Pystagram</title>
  <link rel="stylesheet" href="{% static 'css/bootstrap.css' %}">
</head>
<body>
<nav class="d-flex justify-content-between py-2 px-4 bg-black text-white">
    <div>
{#    TODO : main 연결    #}
        <a href="" class="text-decoration-none text-white"></a>
    </div>
    <div class="text-end">
        {% if request.user.is_authenticated %}
          {{ request.user.nickname }}
          <form action="{% url 'logout' %}" method="post" class="d-inline ms-2">
            {% csrf_token %}
            <button class="btn btn-dark btn-sm">로그아웃</button>
          </form>
        {% else %}
          <a class="btn btn-dark btn-sm" href="{% url 'signup' %}">회원가입</a>
          <a class="btn btn-dark btn-sm" href="{% url 'login' %}">로그인</a>
        {% endif %}
    </div>
</nav>
  <div class="container">
    {% block content %}{% endblock %}
  </div>
  <script src="{% static 'js/bootstrap.bundle.js' %}"></script>
</body>
</html>

settings.py 에 리다이렉트 설정

LOGIN_URL = '/login/'
LOGOUT_REDIRECT_URL = '/'

 


🔐 보안 팁

  • authenticate() 함수는 AUTH_USER_MODEL에 정의된 USERNAME_FIELD 값을 기준으로 인증합니다 (예: email)
  • 로그인 성공 후 반드시 login(request, user) 호출로 세션 처리 필요
  • 로그인 폼의 clean() 메서드에서 사용자 상태도 함께 체크해야 보안상 안전합니다

📌 마무리 체크리스트

  • 로그인 폼 커스텀 생성
  • 로그인 뷰 구현 (GET, POST)
  • 로그아웃 뷰 구현
  • URL 연결 및 템플릿 작성

다음 포스트에서는 ✅ 로그인 상태에 따라 네비게이션 분기 처리나 ✅ 비밀번호 재설정(Reset) 기능으로 이어가보겠습니다!

'Django' 카테고리의 다른 글

Chapter 9-1 Django Post 기능 구현하기  (0) 2025.05.14
🔍 Django에서 User.objects.model의 정체는?  (0) 2025.05.12
Chapter 8-5 Django 이메일 인증을 위한 SMTP 설정 가이드  (0) 2025.05.12
Chapter 8-4 환경변수 관리와 python-dotenv 사용법  (0) 2025.05.12
Chapter 8-3 Django 회원가입 페이지 만들기 (정적 파일 + 폼 커스텀 + 뷰 구현)  (0) 2025.05.12
  1. 🔥 Mini Project: Django Login & Logout 기능 만들기
  2. ✅ 핵심 개념 정리
  3. ✅ 로그인 폼 정의하기 (LoginForm)
  4. ✅ 로그인 뷰 작성
  5. ✅ URL 연결
  6. ✅ 로그인 템플릿 (login.html)
  7. 🔐 보안 팁
  8. 📌 마무리 체크리스트
'Django' 카테고리의 다른 글
  • Chapter 9-1 Django Post 기능 구현하기
  • 🔍 Django에서 User.objects.model의 정체는?
  • Chapter 8-5 Django 이메일 인증을 위한 SMTP 설정 가이드
  • Chapter 8-4 환경변수 관리와 python-dotenv 사용법
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)
  • 블로그 메뉴

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

  • 공지사항

  • 인기 글

  • 태그

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

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
Chansman
Chapter 8-6 Mini Project: Django Login & Logout 기능 만들기

개인정보

  • 티스토리 홈
  • 포럼
  • 로그인
상단으로

티스토리툴바

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.