본문 바로가기

TIl

Authentication 2

회원 가입:

User 객체를 Create 하는 과정

UserCreationForm():

회원 가입시 사용자 입력 데이터를 받는 built-in MdelForm

# accouts/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이 기존 유저 모델로 인해 작성된 클래스이기 때문
  • ⇒ 대체한 유저 모델로 변경이 필요함

커스텀

# 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):
        # 현재 django 프로젝트에 활성화 된 User 객체를 반환하는 함수
        model = get_user_model()

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

왜 User 모델을 직접 참조하지 않는가? get_user_model()을 사용해 User 모델을 참조하면 커스텀 User 모델을 자동으로 반환해주기 때문 ⇒ Django에서 get_user)model()을 사용해 참조해야 한다고 강조함

def signup(request):
    if  request.user_is_authenticated:
        return redirect('articles:index')
    
    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 , index.html 에도 추가

# accounts/views.py

def delete(Request):
	request.user.delete()
	return redirect('articles:index')

유저 정보 Update

User 객체를 Update 하는 과정

UserChangeForm :

회원정보 수정 시 사용자 입력 데이터를 받는 built-in ModelForm

# forms.py
class CustomUserChangeForm(UserChangeForm):
    class Meta(UserChangeForm.Meta):
        # 현재 django 프로젝트에 활성화 된 User 객체를 반환하는 함수
        model = get_user_model()
        fields = ('first_name','last_name','email') # 출력 필드 재 정의
# views.py
from .forms import CustomUserChangeForm

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)

UserChangeForm 사용 시 문제점

  • User 모델의 모든 정보들(fields)까지 모두 출력되어 수정이 가능하기 때문에 일반 사용자들이 접근해서는 안되는 정보는 출력하지 않도록 해야 함

⇒ CustomUserChangeForm에서 접근 가능한 필드를 다시 조정

UserChangeForm 은 관리자 수정폼을 가져오기 때문에, 실제 쓰기 위해서는 조금 더 커스텀이 필요하다.

django user object ⇒ django.contrib.auth 공식문서에서 User model에 대한 필드 명을 알 수 있다.

비밀번호 변경

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

PasswordChangeForm()

비밀번호 변경 시 사용자 입력을 받는 built-in form

# accounts/views.py

from django.contrib.auth.forms import PasswordChangeForm

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:
        # PasswordChangeForm은 첫번째 인자 user가 필수이다.
        form =  PasswordChangeForm(request.user)
    context = {
        'form':form
    }
    return render(request, 'accounts/change_password.html', context)

비밀번호 변경 페이지 작성

DJANGO는 비밀번호 변경 페이지를 회원정보 수정 FORM에서 별도 주소로 안내

⇒ /user_pk/password/로 보내버림

*****************
# 프로젝트/ urls.py
*****************

form accounts import views

urlpatterns = [
path('<int:user_pk>/password/', views.change_password, name='change_password'),
]
<!-- accounts/change_password.html -->
<form action="{% url 'change_password' user.pk %}" method="POST">

세션 무효화

암호 변경 시 세션 무효화

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

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 form.is_valid():
    user = form.save()
    update_session_auth_hash(request, user)
    return redirect('articles:index')

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

로그인 사용자에 대해 접근을 제한하는 2가지 방법

  1. is_authenticated 속성 ( attribute)
  2. login_required 데코레이터 (decorator)

is_authenticated

사용자가 인증 되었는지 여부를 알 수 있는 User model의 속성 , True / False

모든 User 인스턴스에 대해 항상 True인 읽기 전용 속성, 비인증 사용자(=익명의 사용자)에 대해서는 항상 False

<!-- html -->
<!-- 로그인과 비로그인 상태에서 화면에 출력되는 링크를 다르게 설정하기 -->

{% if request.user.is_authenticated %}
~~~
{% endif %}
# views.py
# 인증된 사용자라면 로그인 / 회원가입 로직을 수행할 수 없도록 하기
def login(request):
    if  request.user.is_authenticated:
        return redirect('articles:index')
    
    if request.method == 'POST':
        form = AuthenticationForm(request, request.POST)
        if form.is_valid():
            auth_login(request, form.get_user())
            return redirect('articles:index')

login_required

인증된 사용자에 대해서만 view 함수를 실행시키는 데코레이터

⇒ 비인증 사용자의 경우 /accounts/login/ ( 정해져 있음 ) 주소로 redirect 시킴

# 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 create(update, article_pk):
	pass
# 인증된 사용자만 로그아웃/탈퇴/수정/비밀번호 변경 할 수 있도록 수정

@login_required
def logout(request):
	pass
# ... delete, update, change_password 등

회원가입 + 로그인

# views.py
# 회원가입 요청 폼
    form = CustomUserCreationForm(request.POST)
    if form.is_valid():
		    # form.sava()
        user = form.save()
        auth_login(request,user) # 회원가입 + 로그인
        return redirect('articles:index')

탈퇴 + 기존 사용자 Session Data 삭제

  • 사용자 객체 삭제 이후 로그아웃 함수 호출
  • 단 탈퇴 → 로그아웃 의 순서를 지켜야함
  • 먼저 로그아웃이 진행되면 해당 요청 객체 정보가 없어짐 ⇒ 탈퇴에 필요한 유저 정보 또한 없어짐
# views.py

def delete(request):
	request.user.delete()
	auth_logout(request)

왜 PasswordChangeForm은 다른 Form과 달리 user 객체를 첫번째 인자로 받을 까?

부모 클래스인 SetPasswordForm의 생성자 함수 구성을 따르기 때문

'TIl' 카테고리의 다른 글

REST API 1  (0) 2024.04.16
SQL  (1) 2024.04.16
Authentication  (0) 2024.04.16
Statics  (1) 2024.04.16
Form  (0) 2024.04.16