본문 바로가기
Django

Django 회원가입 기능 추가하기

by 개발자54 2022. 12. 1.

※ 이 포스트는 <Django로 쉽게 배우는 배프의 오지랖 파이썬 웹 프로그래밍>을 참고하여 작성하였습니다.

 

1. 회원가입 양식 폼 작성

# accounts/forms.py

from django.contrib.auth.models import User
from django import forms

class RegisterForm(forms.ModelForm):
    password = forms.CharField(label='Password', widget=forms.PasswordInput)
    password2 = forms.CharField(label='Repeat Password', widget=forms.PasswordInput)

    class Meta:
        model = User
        fields = ['username', 'first_name', 'last_name', 'email']

    def clean_password2(self):
        cd = self.cleaned_data
        if cd['password'] != cd['password2']:
            raise forms.ValidationError('Passwords not matched!')
        return cd['password2']
  • RegisterForm : forms.ModelForm을 상속받으며, 모델이 있고 그에 대한 자료를 입력받고 싶을 때 사용
  • Meta 클래스 : 기존에 있는 모델의 입력 폼을 쉽게 만들고자 할 때 사용, model을 통해 사용할 모델을 설정하고 fields를 통해 입력받을 필드들을 지정
  • password의 경우는 별도의 widger 옵션을 사용해 password 속성의 input 태그를 사용하기 위해 클래스 변수로 따로 지정
  • clean_password2 메서드는 각 필드의 clean 메서드가 호출된 후에 호출되는 메서드. 특별한 유효성 검사나 조작을 하고 싶을 때 만들어서 사용함. password와 password2가 같은지 비교하는 코드 용도
  • clean_ 필드명 형태의 메서드에서 해당 필드의 값을 사용할 때는 꼭 cleaned_deta에서 필드 값을 찾아서 사용해야 함. 이 값은 이전 단계까지 기본 유효성 검사와 같은 처리를 마친 값이기 때문

 

 

2. 함수형 뷰 작성

# accounts/views.py

from django.shortcuts import render
from .forms import RegisterForm

def register(request):
    if request.method == 'POST':
        user_form = RegisterForm(request.POST)
        if user_form.is_valid():
            new_user = user_form.save(commit=False)
            new_user.set_password(user_form.cleaned_data['password'])
            new_user.save()
            return render(request, 'registration/register_done.html', {'new_user':new_user})
    else:
        user_form = RegisterForm()

        return render(request, 'registration/register.html', {'form':user_form})

이하는 코드 설명 주석

# accounts/views.py

from django.shortcuts import render
from .forms import RegisterForm

def register(request):
    if request.method == 'POST':
    # 회원 가입 정보가 서버로 전달되었는가? 확인
        user_form = RegisterForm(request.POST)
        # 정보가 서버로 전달되었다면, RegisterForm을 통해 유효성 검사를 수행
        if user_form.is_valid():
            new_user = user_form.save(commit=False)
            # 폼 객체에 지정된 모델을 확인하고, 메모리 상에 모델의 객체를 만든다. (commit=False이므로 데이터베이스에 저장하는 것은 아님)
            new_user.set_password(user_form.cleaned_data['password'])
            # 비밀번호 지정
            new_user.save()
            # 실제로 데이터베이스에 저장
            return render(request, 'registration/register_done.html', {'new_user':new_user})
            # 회원가입이 완료되면 register_done이라는 템플릿을 렌더링해 보여줌
    else:
    # HTTP 메서드가 POST가 아니라면, 자료를 전달받은 상태가 아니므로
        user_form = RegisterForm()
        # 비어 있는 RegisterForm 객체를 만들고
        return render(request, 'registration/register.html', {'form':user_form})
        # register 템플릿을 렌더링해 보여줌

 

 

3. URL 연결

# accounts/urls.py

from django.urls import path
from django.contrib.auth import views as auth_view
# 추가한 코드
from .views import register
# 추가한 코드 끝

urlpatterns = [
    path('login/', auth_view.LoginView.as_view(), name='login'),
    path('logout/', auth_view.LogoutView.as_view(template_name='registration/logout.html'), name='logout'),
    # 추가한 코드
    path('register/', register, name='register'),
    # 추가한 코드 끝
]

 

 

4. 회원가입 페이지 템플릿 작성

<!-- accounts/templates/registration/register.html -->

{% extends 'base.html' %}

{% block title %}회원가입{% endblock %}

{% block content %}
<div class="row">
    <div class="col-md-2"></div>
    <div class="col-md-8 panel panel-default">
        <div class="alert alert-info">정보를 입력하세요.</div>
        <form action="" method="post">
            {{form.as_p}}
            {% csrf_token %}
            <input class="btn btn-primary" type="submit" value="Register">
        </form>
    </div>
    <div class="col-md-2"></div>
</div>
{% endblock %}

 

 

5. 회원가입 완료 페이지 템플릿 작성

<!-- accounts/templates/registration/register_done.html -->

{% extends 'base.html' %}

{% block title %}회원가입 완료{% endblock %}

{% block content %}
<div class="row">
    <div class="col-md-2"></div>
    <div class="col-md-8 panel panel-default">
        <div class="alert alert-info">가입이 완료되었습니다. 환영합니다, {{new_user.username}}님!</div>
        <a class="btn btn-info" href="/fst">메인으로</a>
        </form>
    </div>
    <div class="col-md-2"></div>
</div>
{% endblock %}

 

 

6. base.html에 회원가입 링크 연결

<!-- templates/base.html -->

...
    <div class="collapse navbar-collapse" id="navbarSupportedContent">
        <ul class="navbar-nav mr-auto">
            <li class="nav-item active">
                <a class="nav-link" href="#">Home <span class="sr-only">(current)</span></a>
            </li>
            {% if user.is_authenticated %}
            <li class="nav-item"><a href="{% url 'logout' %}" class="nav-link">로그아웃</a></li>
            {% else %}
            <li class="nav-item"><a href="{% url 'login' %}" class="nav-link">로그인</a></li>
            <!-- 추가한 코드 -->
            <li class="nav-item"><a href="{% url 'register' %}" class="nav-link">회원가입</a></li>
            <!-- 추가한 코드 끝 -->
            {% endif %}
        </ul>
    </div>
...

 

 

7. 서버 실행하여 결과 확인

$ python manage.py runserver

회원가입 버튼을 누르면 회원 가입 화면으로 잘 이동한다. 정보를 입력하고 Register 버튼을 누르면,

 

가입이 완료되고, 완료 화면도 잘 뜬다.

 

가입한 정보로 로그인을 해보면,

 

로그인도 잘 되어서 로그아웃 버튼이 뜨는 것을 알 수 있다.

 

 

8. 관리자 계정으로 로그인하여 유저 정보 확인

관리자 페이지에 접속하여 로그인

 

Users 클릭

 

입력한 정보대로 유저 정보가 잘 들어와있는 것을 확인할 수 있다.

회원가입이 완료되었다.

 


 

번외. DB 클라이언트 툴로 테이블 데이터 확인 + Django의 암호화?

이번엔 TablePlus에 접속하여 DB 데이터들을 확인해보자.

현재 공공데이터를 저장하는 데에 postgreSQL DB를 사용하고 있으므로

User의 정보들 또한 당연히 postgerSQL DB에 저장되어 있다.

 

auth_user라는 테이블에 관리자를 비롯하여 회원가입한 유저들의 정보가 저장되어있다.

DB를 보면서 내가 가장 신기했던 건 password 부분이었는데,

Django는 기본적으로 암호화 알고리즘(PBKDF2)을 제공하고 있어서

사용자가 별도로 암호화 처리를 하지 않아도 된다.

이게 굉장히 편리했다.

 

그런데 Django의 암호화와 관련해서 검색해본 결과,

기본 제공 암호화 함수 보다는

차세대 암호화 알고리즘인 Argon2 라이브러리를 받아 사용하는 것을 권장한다고 한다.

 

공식 문서에도 이렇게 쓰여있다.

(https://docs.djangoproject.com/en/4.1/topics/auth/passwords/ 참고)

Argon2 is the winner of the 2015 Password Hashing Competition,
a community organized open competition to select a next generation hashing algorithm.

It’s designed not to be easier to compute on custom hardware than it is to compute on an ordinary CPU.
Argon2 is not the default for Django because it requires a third-party library.
The Password Hashing Competition panel,
however, recommends immediate use of Argon2 rather than the other algorithms supported by Django.

요약하면 Argon2이 암호 해싱 경쟁에서 우승했고 Django 내의 다른 암호화 알고리즘보다 좋으니 사용하는걸 권고한다는 이야기.

(Django 공식 사이트에서 대놓고 이거 써라! 라고 하진 않고 암호 해싱 경쟁 패널들이 추천한다고 간접적으로 쓰여있다.)

 

다음에는 Agron2 라이브러리를 설치해서 암호화를 적용해봐야겠다.

댓글