Django 인증 시스템의 핵심 구성 요소

1. 쿠키 기반 세션 관리

HTTP 프로토콜은 상태 없음(stateless) 특성을 지녀, 사용자가 로그인 후 페이지 이동 시 다시 인증이 필요하게 됩니다. 이를 해결하기 위해 쿠키가 도입되었습니다. 서버는 클라이언트 요청 시 고유한 식별자(쿠키 값)를 생성하여 전달하고, 이후 요청에서 해당 쿠키를 확인함으로써 사용자의 정체를 파악합니다.

쿠키는 최대 4096바이트 제한이 있으며, 직접 데이터 저장에 취약하므로 보안상 한계가 있습니다. 이로 인해 세션 시스템이 등장했습니다. 세션은 클라이언트에 세션 ID만 저장하고, 실제 데이터는 서버에 보관하며, 더 안전한 인증 방식을 제공합니다.

기본 쿠키 사용 예제 (일반형)

views.py
from django.shortcuts import render, redirect
from .models import UserInfo

def login_view(request):
    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')
        
        user = UserInfo.objects.filter(name=username, pwd=password).first()
        if user:
            response = redirect('/dashboard/')
            response.set_cookie('is_authenticated', True, max_age=300)
            response.set_cookie('username', username)
            return response
    return render(request, 'login.html')

def dashboard(request):
    if not request.COOKIES.get('is_authenticated'):
        return redirect('/login/')
    username = request.COOKIES.get('username')
    return render(request, 'dashboard.html', {'user': username})

def logout_view(request):
    response = redirect('/login/')
    response.delete_cookie('username')
    return response

암호화된 쿠키 사용 (보안 강화)

views.py
from django.shortcuts import render, redirect
from django.http import HttpResponse
from django.utils.crypto import get_random_string

def require_auth(view_func):
    def wrapper(request, *args, **kwargs):
        user = request.get_signed_cookie('auth_token', default=None, salt='secure_salt_2025')
        if user == 'admin_user':
            return view_func(request, *args, **kwargs)
        return HttpResponse('권한 없음', status=403)
    return wrapper

def login_secure(request):
    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')
        
        if username == 'admin' and password == 'secret123':
            response = redirect('/secure_page/')
            response.set_signed_cookie('auth_token', 'admin_user', salt='secure_salt_2025')
            return response
    return render(request, 'login.html')

@require_auth
def secure_page(request):
    return HttpResponse('안전한 페이지 접근 성공')

2. 세션 시스템 활용

세션은 클라이언트의 브라우저에 세션 ID를 저장하고, 해당 ID에 맞는 데이터는 서버 내부에서 관리하는 구조입니다. Django에서는 request.session 객체를 통해 쉽게 접근 가능합니다.

views.py
def login_session(request):
    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')
        
        user = UserInfo.objects.filter(name=username, pwd=password).first()
        if user:
            request.session['current_user'] = username
            return redirect('/profile/')
    return render(request, 'login.html')

def profile(request):
    username = request.session.get('current_user')
    if not username:
        return redirect('/login_session/')
    return render(request, 'profile.html', {'user': username})

def logout_session(request):
    request.session.flush()  # 전체 세션 삭제
    return redirect('/login_session/')

세션 주요 작업 메서드 요약

  • 설정: request.session['key'] = value
  • 읽기: value = request.session['key']
  • 삭제: del request.session['key']
  • 확인: if 'key' in request.session:

3. Django 기본 인증 시스템 (auth 모듈)

Django는 django.contrib.auth를 통해 사용자 인증, 권한 부여, 그룹 관리 등의 기능을 제공합니다. 이는 내부적으로 세션을 자동으로 관리합니다.

관리자 계정 생성

python manage.py createsuperuser
# 입력 예: 이름: admin, 비밀번호: strongpass123

로그인 처리 예제

views.py
from django.contrib import auth
from django.shortcuts import render, redirect

def auth_login(request):
    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')
        
        user = auth.authenticate(request, username=username, password=password)
        if user is not None:
            auth.login(request, user)
            return redirect('/home/')
        else:
            return render(request, 'login.html', {'error': '아이디 또는 비밀번호 오류'})
    return render(request, 'login.html')

def home(request):
    if not request.user.is_authenticated:
        return redirect('/login/')
    return render(request, 'home.html', {'user': request.user.username})

def auth_logout(request):
    auth.logout(request)
    return redirect('/login/')

사용자 등록 및 비밀번호 변경

views.py
from django.contrib.auth.models import User

def register_user(request):
    if request.method == 'POST':
        username = request.POST.get('username')
        email = request.POST.get('email')
        password = request.POST.get('password')
        
        if User.objects.filter(username=username).exists():
            return render(request, 'register.html', {'error': '이미 존재하는 사용자입니다.'})
        
        User.objects.create_user(username=username, email=email, password=password)
        return redirect('/login/')
    return render(request, 'register.html')

@login_required
def change_password(request):
    if request.method == 'POST':
        old_pass = request.POST.get('old_password')
        new_pass = request.POST.get('new_password')
        confirm_pass = request.POST.get('confirm_password')
        
        if not request.user.check_password(old_pass):
            return render(request, 'change_password.html', {'error': '현재 비밀번호가 올바르지 않습니다.'})
        if new_pass != confirm_pass:
            return render(request, 'change_password.html', {'error': '비밀번호가 일치하지 않습니다.'})
        
        request.user.set_password(new_pass)
        request.user.save()
        return redirect('/login/')
    return render(request, 'change_password.html')

사용자 모델 확장 (커스텀 유저 모델)

기본 User 모델에 추가 필드를 포함시키고자 할 경우, AbstractUser를 상속하여 커스텀 모델을 생성해야 합니다.

settings.py
AUTH_USER_MODEL = 'app01.CustomUser'

models.py
from django.contrib.auth.models import AbstractUser
from django.db import models

class CustomUser(AbstractUser):
    phone = models.CharField(max_length=15, blank=True, null=True)
    birth_date = models.DateField(null=True, blank=True)

이렇게 설정하면 기존 auth_user 테이블과 병합되어 새로운 커스텀 테이블로 작동합니다.

태그: Django authentication Session cookie auth module

6월 11일 23:59에 게시됨