[Django] Login/Logout, 회원가입/회원탈퇴 기능 구현

송수빈·2026년 5월 9일

SSAFY

목록 보기
12/18

Login

  • Login
    • 클라이언트와 서버 간의 상태 정보를 유지하기 위해서 쿠키와 세션을 사용
    • 클라이언트와 서버는 각기 다른 사용자를 식별해야 하는 상태
    • 서버에 ‘나’임을 인증하는 과정이 바로 Login
    • 결국 Login은 인증(id/password)를 완료하고, Session을 만들고 클라이언트와 연결하는 것
  • 로그인 흐름
    1. 로그인 성공
    2. 서버가 세션 생성 (user 정보 저장)
    3. session_id 발급
    4. 브라우저 쿠키에 저장
    5. 이후
      1. 요청 보낼 때마다 쿠키에 session_id 포함
      2. 서버가 확인 → 로그인 유지
  • 로그인 기능 구현
    • 로그인 경로 url 및 링크 생성
      • accounts/urls.py
        app_name = 'accounts'
        urlpatterns = [
        	path('login/', views.login, name='login'),
        ]
      • articles/index.html
        <h1>메인 페이지</h1>
        <a href="{% url "accounts:login" %}">Login</a>
    • …/accounts/login/ url로 요청이 들어왔을 때 실행할 login 함수 작성
      • 로그인 인증에 사용할 데이터를 입력 받는 built-in form (AuthenticationForm) 사용
      • accounts/views.py
        from django.contrib.auth.forms import AuthenticationForm
        
        def login(request):
        		if request.method == 'POST':
        				pass
        		else:
        				form = AuthenticationForm()
        		context = {
        				'form': form,
        		}
        		return render(request, 'accounts/login.html', context)
      • AuthenticationForm()
        • 로그인 인증에 사용할 데이터를 입력 받는 built-in form
        • User 모델과 직접 연결된 ModelForm이 아닌, 일반 Form을 상속 받음
        • 일반 Form이기 때문에 사용자를 생성하거나 수정하는 용도가 아닌 인증하는 역할만 수행
    • 로그인 정보를 서버에 안전하게 전송하기 위해 POST 방식을 사용
      • CSRF 공격을 방지하기 위해 csrf_token 작성
      • 서버로부터 전달받은 AuthenticationForm을 화면에 출력
      • accounts/login.html
        <h1>로그인</h1>
        <form action="{% url 'accounts:login' %}" method="POST">
        	{% csrf_token %}
        	{{ form }}
        	<input type="submit">
        <\form>
    • 사용자가 입력한 로그인 정보를 입력받는 로직을 “POST” 조건문에 작성
      • 입력 받은 정보를 기반으로 로그인하여 세션을 만드는 login 함수를 활용
      • accounts/views.py
        from django.contrib.auth import login as auth_login
        
        def login(request):
        	if request.method == 'POST':
        		form = AuthenticationForm(request, request.POST)
        		if form.is_valid():
        			auth_login(request, form.get_user())
        				return redirect('articles:index')
        	else:
        		form = AuthenticationForm()
        	context = {
        		'form': form,
        	}
        	return render(request, 'accounts/login.html', context)
        • login(request, user) : AuthenticationForm을 통해 인증된 사용자를 로그인하는 함수

          • request: 현재 사용자의 세션 정보에 접근하기 위해 사용
          • user: 어떤 사용자가 로그인 되었는지를 기록하기 위해 사용
        • get_user() : AuthenticationForm의 인스턴스 메서드

          ⇒ 유효성 검사를 통과했을 경우, 로그인 한 사용자 객체를 반환

  • 세션 데이터 확인하기
    • 로그인 후 발급받은 세션 확인
      • django_session 테이블에서 확인
    • 브라우저에서 확인
      • 개발자도구 > Application > Cookies

Template with Authentication data

  • Template with Authentication data
    • 템플릿에서 인증 관련 데이터를 출력하는 방법
  • 현재 로그인 되어있는 유저 정보 출력하기
    • user라는 context 데이터를 사용할 수 있는 이유는, django가 미리 준비한 context 데이터가 존재하기 때문 (context processors)
    • articles/index.html
      <h3>Hello, {{ user.username }}</h3>
    • context processors ('django.contrib.auth.context_processors.auth')
      • 템플릿이 렌더링될 때 호출 가능한 컨텍스트 데이터 목록
      • 작성된 컨텍스트 데이터는 기본적으로 템플릿에서 사용 가능한 변수로 포함됨
      • django에서 자주 사용하는 데이터 목록을 미리 템플릿에 로드해둔 것

Logout

  • Logout
    • 로그아웃은 Session을 Delete하는 과정
    • 서버의 세션 데이터를 비우고, 클라이언트의 세션 쿠키를 삭제
  • logout(request)
    • DB에서 현재 요청에 대한 Session Data를 삭제
    • 클라이언트의 쿠키에서도 Session ID를 삭제
  • 로그아웃 기능 구현
    • 로그아웃 경로 url 및 링크 생성
      • accounts/urls.py
        urlpatterns = [
        	path('login/', views.login, name='login'),
        	path('logout/', views.logout, name='logout'),
        ]
    • …/accounts/logout/ url로 요청이 들어왔을 때 실행할 logout 함수 작성
      • DB에서 현재 요청에 대한 Session Data를 삭제하고, 클라이언트의 쿠키에서도 Session ID를 삭제하는 내장 logout 함수 작성
      • accounts/views.py
        from django.contrib.auth import logout as auth_logout
        
        def logout(request):
        	auth_logout(request)
        	return redirect('articles:index')
    • 로그인한 사용자 정보를 서버에 안전하게 전송하기 위해 “POST 방식”을 사용
      • CSRF 공격을 방지하기 위해 csrf_token 작성
      • articles/index.html
        <h1>메인 페이지</h1>
        <a href="{% url "accounts:login" %}">Login</a>
        <form action="{% url "accounts:logout" %}" method="POST">
        	{% csrf_token %}
        	<input type="submit" value="Logout">
        </form>

회원 가입

  • 회원 가입
    • User 객체를 Create하는 과정
    • 사용자로부터 아이디, 비밀번호 등의 정보를 입력 받아, DB에 새로운 User 객체를 생성하고 저장
  • 회원 가입 기능 구현
    • 회원가입 경로 url 및 링크 생성
      • accounts/urls.py
        urlpatterns = [
        	path('login/', views.login, name='login'),
        	path('logout/', views.logout, name='logout'),
        	path('signup/', views.signup, name='signup'),
        ]
      • articles/index.html
        <h1>메인 페이지</h1>
        <a href="{% url "accounts:login" %}">Login</a>
        <form action="{% url "accounts:logout" %}" method="POST">
        	{% csrf_token %}
        	<input type="submit" value="Logout">
        </form>
        <a href="{% url "accounts:signup" %}">회원가입</a> |
    • …/accounts/signup/ url로 요청이 들어왔을 때 실행할 signup 함수 작성
      • 회원가입에 사용할 데이터를 입력 받는 UserCreationForm built-in form 사용
      • accounts/views.py
        from django.contrib.auth.forms import UserCreationForm
        
        def signup(request):
        	if request.method == "POST":
        		pass
        	else:
        		form = UserCreationForm()
        	
        	context = {
        		'form': form,
        	}
        	return render(request, 'accounts/signup.html', context)
      • UserCreationForm()
        • 회원 가입시 사용자 입력 데이터를 받는 built-in ModelForm
        • ModelForm이기 때문에, 유효성 검사를 통과한 데이터로 새로운 User 객체를 생성하고 데이터베이스에 저장하는 역할을 수행 (이때 비밀번호는 자동으로 암호화됨)
    • 회원가입을 위해 작성한 정보를 서버에 안전하게 전송하기 위해 “POST 방식”을 사용
      • CSRF 공격을 방지하기 위해 csrf_token 작성
      • 서버로부터 전달받은 UserCreationForm을 화면에 출력
      • accounts/signup.html
        <h1>Signup</h1>
        <hr>
        <form action="{% url "accounts:signup" %}" method="POST">
            {% csrf_token %}
            {{ form }}
            <input type="submit">
        </form>
    • 회원 가입 기능 에러 발생 및 해결
      • 회원가입 시도 후 에러 페이지 확인
        Manager isn't available; 'auth.User' has been swapped for 'accounts. User'
      • 회원가입에 사용하는 UserCreationForm이 대체한 커스텀 유저 모델이 아닌 과거 Django의 기본 유저 모델로 인해 작성된 클래스이기 때문 ⇒ model에 Custom User Model을 연결하자!
    • 커스텀 유저 모델을 사용하기 위해서 Form을 다시 작성
      • Custom User model을 사용할 수 있도록 상속 후 일부분만 재작성
      • accounts/forms.py
        from django.contrib.auth import get_user_model
        from django.contrib.auth.forms import UserCreationForm
        
        class CustomCreationForm(UserCreationForm):
        	class Meta(UserCreationForm.Meta):
        		model = get_user_model()
      • get_user_model()
        • 현재 프로젝트에서 활성화된 사용자 모델(active user model)을 반환하는 함수
        • Django는 필수적으로 User 클래스를 직접 참조하는 대신 get_user_model()을 사용해 참조해야 한다고 강조하고 있음
    • 회원 가입 로직 완성
      • 내장 Form이었던 UserCreationForm을 CustomUserCreationForm으로 변경
      • accounts/views.py
        from .forms import CustomUserCreationForm
        
        def signup(request):
        	if request.method == 'POST':
        		form = CustomUserCreationForm(request.POST)
        		if form.is_valid():
        			form.save()
        			return redirect('articles:index')
        	else:
        		form = CustomUserCreationForm()
        		
        	context = {
        		'form': form,
        	}
        	return render(request, 'accounts/signup.html', context)

회원 탈퇴

  • 회원 탈퇴
    • User 객체를 Delete하는 과정
    • request.user.delete()를 활용해서 유저 객체 삭제를 진행
  • 회원 탈퇴 로직 작성
    • 회원 탈퇴 경로 url 및 링크 생성
      • account/urls.py
        urlpatterns = [
        	path('login/', views.login, name='login'),
        	path('logout/', views.logout, name='logout'),
        	path('signup/', views.signup, name='signup'),
        	path('delete/', views.delete, name='delete'),
        ]
      • articles/index.html
        <form action="{% url "accounts:delete" %}" method="POST">
        	{% csrf_token %}
        	<input type="submit" value="회원탈퇴">
        </form>
    • …/accounts/delete/ url로 요청이 들어왔을 때 실행할 delete 메서드 작성
      • 현재 로그인한 사용자 정보를 활용해 삭제하고, 메인 페이지로 이동
      • accounts/views.py
        def delete(request):
        	request.user.delete()
        	return redirect('articles:index')

인증된 사용자에 대한 접근 제한

is_authenticated 속성

  • is_authenticated 속성
    • 사용자가 인증되었는지 여부를 알 수 있는 User model의 읽기 전용 속성
    • 인증 사용자에 대해서는 항상 True, 비인증 사용자에 대해서는 항상 False
    • 사용되는 경우
      • 사용자의 로그인 상태에 따라 다른 메뉴를 보여줄 때
      • view 함수 내에서 특정 기능을 로그인한 사용자에게만 허용하고 싶을 때
  • is_authenticated 적용하기
    • 로그인과 비로그인 상태에서 화면에 출력되는 링크를 다르게 설정하기
      • articles/index.html
        {% if request.user.is_authenticated %}
        ...
        {% else %}
        	<a href="{% url 'accounts:login' %}">Login</a>
        	<a href="{% url 'accounts:signup' %}">Signup</a>
        {% endif %}
    • 인증된 사용자라면 로그인/회원가입 로직을 수행할 수 없도록 하기
      • accounts/views.py
        def login(request):
        	if request.user.is_authenticated:
        		return redirect('articles:index')
        	...
        
        def signup(request):
        	if request.user.is_authenticated:
        		return redirect('articles:index')
        	...

login_required 데코레이터

  • login_required 데코레이터
    • 인증된 사용자에 대해서만 view 함수를 실행시키는 데코레이터
    • 비인증 사용자의 경우 /accounts/login/ 주소로 redirect 시킴
    • 사용되는 경우
      • 게시글 작성, 댓글 달기 등 누가 작성했는지 중요한 곳에서 사용
  • login_required 적용하기
    • 인증된 사용자만 게시글을 작성/수정/삭제할 수 있도록 수정
      • articles/views.py
        from django.contrib.auth.decorators import login_required
        
        @login_required
        def create(request):
        	pass
        
        @login_required
        def delete(request, article_pk):
        	pass
        
        @login_required
        def update(request, article_pk):
        	pass
    • 인증된 사용자만 로그아웃/탈퇴/수정/비밀번호 변경 할 수 있도록 수정
      • accounts/views.py
        from django.contrib.auth.decorators import login_required
        
        @login_required
        def logout(request):
        	pass
        
        @login_required
        def delete(request):
        	pass
        
        @login_required
        def update(request):
        	pass
        
        @login_required
        def change_password(request):
        	pass
profile
🌱 🐜

0개의 댓글