[Django] Authentication system 2

Jingi·2024년 4월 1일

Web

목록 보기
15/40
post-thumbnail

회원 가입

  • User 객체를 Create 하는 과정

UserCreationForm()

  • 회원 가입시 사용자 입력 데이터를 받는 built-int ModelForm
# urls.py
from django.urls import path
from . import views

app_name = 'accounts'
urlpatterns = [
    path('signup/', views.signup, name='signup'),
]
<h1>회원가입</h1>
<form action="{% url 'accounts:signup' %}" method="POST">
    {% csrf_token %}
    {{form.as_p}}
    <input type = "submit">
</form>
# views.py
def signup(request):
    if request.method == 'POST':
        form = UserCreationForm(request.POST)
        if form.is_valid():
            form.save()
            return redirect('articles:index')
    else:
        form = UserCreationForm()
        context = {
            'form' : form,
        }
    return render(request, 'accounts/signup.html', context)
    

회원 가입 로직 에러

  • 회원 가입에 사용하는 UserCreationForm이 기존 유저 모델로 인해 작성된 클래스이기 때문
  • 대체한 유저 모델로 변경 필요
class Meta:
    model = user
    fields = ("username",)
    field_classes = {"username": UsernameField}
# accounts/forms.py

from django.contrib.auth import get_user_model
from django.contrib.auth.forms import UserCreationForm, UserChangeForm

class CustomUserCreationForm(UserCreationForm):
    class Meta(UserCreationForm.Meta):
        model = get_user_model()

class CustomUserChangeForm(UserChangeForm):
    class Meta(UserChangeForm.Meta):
        model = get_user_model()

get_user_model()

  • 현재 프로젝트에서 활성화된 사용자 모델(active user model)을 반환하는 함수

User 모델을 직접 참조하지 않는 이유

  • get_user_model()을 사용해 User 모델을 참조하면 커스텀 User 모델을 자동으로 반환해주기 때문
  • Django는 필수적으로 User 클래스를 직접 참조하는 대신 get_user_model()을 사용해 참조해야 한다고 강조하고 있음.

회원가입 로직 custom 적용

# 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 하는 과정
# urls.py
app_name = 'accounts'
urlpatterns = [
    path('delete/', views.delete, name='delete'),
]
<form action="{% url 'accounts:delete' %}" method = "POST">
  {% csrf_token %}
  <input type="submit" value="회원탈퇴">
</form>
# views.py
def delete(request):
    request.user.delete()
    return redirect('articles:index')

회원정보 수정

  • User 객체를 Update하는 과정

UserChangeForm()

  • 회원정보 수정 시 사용자 입력 데이터를 받는 built-in ModelForm
# accounts/urls.py
app_name = 'accounts'
urlpatterns = [
    path('update/', views.update, name='update'),
]
<h1>회원정보 수정</h1>
<form action="{% url 'accounts:update' %}" method = "POST">
    {% csrf_token %}
    {{form.as_p}}
    <input type = "submit">
</form>
# accounts/views.py
from .forms import CustomUserChangeForm

def update(request):
     if request.method =='POST':
        pass
    else:
        form = CustomUserChangeForm(instance=request.user)
        context = {
            'form' : form,
        }
    return render(request, 'accounts/update.html', context)
<a href = "{% url 'accounts:update' %}">회원정보 수정</a>

UserChangeForm 사용 시 문제점

  • User 모델의 모든 정보들까지 모두 출력되어 수정이 가능하기 때문에 일반 사용자들이 접근해서는 안되는 정보는 출력하지 않도록 해야 함
  • CustomUserChangeForm에서 접근 가능한 필드를 다시 조정
# forms.py
class CustomUserChangeForm(UserChangeForm):
    class Meta(UserChangeForm.Meta):
        model = get_user_model()
        fields = ('first_name', 'last_name', 'email',)
# views.py
def update(request):
    if request.method == 'POST':
        form = CustomUserChangeForm(request.POST, instance=request.user)
        if form.is_valid():
            form.save()
            return redirect('articles:index')
    else:
        form = CustomUserChangeForm(instance=request.user)
        context = {
            'form' : form,
        }
    return render(request, 'accounts/update.html', context)
    

비밀번호 변경

  • 인증된 사용자의 Session 데이터를 Update 하는 과정

PasswordChangeForm()

  • 비밀번호 변경 시 사용자 입력 데이터를 받는 built-in Form
# accounts/urls.py
app_name = 'accounts'
urlpatterns = [
    path('<int:user_pk>/password', views.change_password, name='change_password'),
]
<h1>회원정보 수정</h1>
<form action="{% url 'change_password' user.pk %}" method = "POST">
    {% csrf_token %}
    {{form.as_p}}
    <input type = "submit">
</form>
# accounts/views.py
from django.contrib.auth.forms import PasswordChangeForm


def change_password(request):
     if request.method =='POST':
        pass
    else:
        form = PasswordChangeForm(request.user)
        context = {
            'form' : form,
        }
    return render(request, 'accounts/change_password.html', context)
# 변경로직 작성
# accounts/views.py

def change_password(request, user_pk):
    if request.method = 'POST':
        form = PasswordChangeForm(request.user, request.POST)
        if form.is_valid():
            form.save()
            return redirect('articles:index')
    else:
        form = PasswordChangeForm(request.user)
        context = {
            'form' : form,
        }
    return render(reqeust, 'accounts/change_password.html', context)

세션 무효화 방지하기

암호 변경 시 세션 무효화

  • 비밀번호가 변경되면 기존 세션과의 회원 인증 정보가 일치하지 않게 되어 버려 로그인 상태가 유지되지 못하고 로그아웃 처리됨
  • 비밀번호가 변경되면서 기존 세션과의 회원 인증 정보가 일치하지 않기 때문

update_session_auth_hash(request, user)

  • 암호 변경 시 세션 무효화를 막아주는 함수
  • 암호가 변경되면 새로운 password의 Session Data로 기존 session을 자동으로 갱신
# 변경로직 작성
# accounts/views.py
from django.contrib.auth import update_session_auth_hash

def change_password(request, user_pk):
    if request.method = 'POST':
        form = PasswordChangeForm(request.user, request.POST)
        if form.is_valid():
            user = form.save()
            update_session_auth_hash(request, user)
            return redirect('articles:index')
    else:
        form = PasswordChangeForm(request.user)
        context = {
            'form' : form,
        }
    return render(reqeust, 'accounts/change_password.html', context)

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

  • is_authenticated 속성
  • login_required 속성

is_authenticated

  • 사용자가 인증되었는지 여부를 알 수 있는 User model의 속성
  • 모든 User 인스턴스에 대해 항상 True인 읽기 전용 속성이며, 비인증 사용자에 대해서는 항상 False
<h1>회원가입</h1>
<form action="{% url 'accounts:signup' %}" method="POST">
    {% csrf_token %}
    {{form.as_p}}
    <input type = "submit">
</form>

{% if reqeust.user.is_authenticated %}
    <h3>Hello, {{user.username}} </h3>
    <a href="{% url 'articles:create' %}">NEW</a>
    <form action="{% url 'accounts:logout' %}" mehtod ="POST">
        {% csrf_token %}
        <input type="submit" value="Logout">
    </form>
    <form action="{% url 'accounts:delete' %}" mehtod ="POST">
        {% csrf_token %}
        <input type="submit" value="회원탈퇴">
    </form>
    <a href="{% url 'accounts:update' %}">회원정보 수정</a>
{% else %}
    <a href="{% url 'accounts:login' %}">Login</a>
    <a href="{% url 'accounts:signup' %}">Signup</a>
{% endif %}

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 

@login_required
def change_password(request):
    pass 
profile
데이터 분석에서 백엔드까지...

0개의 댓글