티스토리 뷰

<Complete List>

1. 데이터베이스 및 UI 설계하기

  • 인스타그램 UI 구성
  • 데이터베이스 테이블 설계 및 구현

2. 앱 만들기

  • instagram, accounts 앱 만들기
  • views.py 분리하기

 

<To Do List>

3. 회원가입 페이지

  • url
  • view
    • 비밀번호 암호화 함수 구현 - 해시 함수
  • template

 


3. 회원가입 페이지

  • accounts 앱에서 작업
  • 일단 Django의 인증 기능을 사용하지 않고 구현해보기

3.1 url

urlpatterns = [
    re_path(r'^register/$', PreRegisterAccountsView, name='pn_reg_accounts'),
]

 

3.2 PreRegisterAccountsView

  • splitviews 디렉토리에 RegisterAccountsView.py 생성

  • splitviews 의 __init.py__에 다음과 같이 PreRegisterAccountsView 를 import

# __init__.py
from .PreRegisterAccountsView import *

 

  1. GET으로 들어올 경우 회원가입 페이지 rendering

  2. POST로 들어올 경우 먼저 사용자가 입력한 form 데이터를 받아온다.

  3. 사용자가 입력한 ID 값을 가진 User가 있는지 User 테이블에서 찾아온다.

    3.1 User가 있다면 "이미 존재하는 아이디" 라는 메시지와 함께 회원가입 페이지 redirect

    3.2 User가 없다면 User 테이블에 새로운 User 데이터 INSERT

  4. 새로운 User 데이터를 INSERT 하기 전 사용자가 입력한 비밀번호 값을 암호화

  5. 4의 값과 2의 값으로 User 테이블에 INSERT

  6. "로그인 해주세요" 라는 메시지와 함께 로그인 페이지 redirect

 

메시지와 redirect 할 때는 messages 프레임워크를 사용

messages.error(request, '이미 존재하는 아이디입니다. 다른 아이디를 사용해주세요.')
return redirect('accounts:pn_reg_accounts')

 

  • 비밀번호 암호화 함수
# RegisterAccountsView.py
salt, hashed_pw = hashing_password(user_pw)

# common.py
import string
import random
import hashlib
import base64
from django.contrib.auth.hashers import pbkdf2

def hashing_password(user_pw):
    # salt 생성 - salt는 최소 128bit 이상이 권고된다 하여 다음과 같이 생성
    count = random.randint(16, 21)
    string_pool = string.ascii_letters + string.digits + string.punctuation
    salt = "".join(random.choices(string_pool, k=count))    # count만큼 문자열을 랜덤 선택하여 합치기

    hash = pbkdf2(user_pw, salt, 10000, digest=hashlib.sha256)
    hashed_pw = base64.b64encode(hash).decode('ascii').strip()

    return salt, hashed_pw

처음에 파이썬의 built-in hash 함수를 사용했는데 같은 input값으로 해시해도 계속 output이 달랐다.

 

구글링을 해보니 다음과 같은 문제가 있었다.

 

그래서 Django가 기본적으로 사용하고 있는 패스워드 시스템에 관한 문서를 찾았고 위와 같이 해시함수를 구현했다.

  • pbkdf2(password, salt, iterations, digest) : Django에서 기본적으로 사용하고 있는 해시 함수

 

해시된 비밀번호와 해시에 함께 사용된 salt 를 함께 return

  • salt를 데이터베이스에 함께 저장하여 로그인 - 비밀번호 비교 시 활용

 

3.3 reg_accounts.html

<!--base.html 확장-->
{% extends 'base.html' %}

<!--static 폴더의 정적 파일 적용-->
{% load static %}
{% block head %}
  <link rel="stylesheet" type="text/css" href="{% static 'css/accounts.css' %}">
{% endblock head %}

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

{% block body %}
<div class="container">
    <div class="row justify-content-center align-items-center">
        <div style="margin-top:100px;">
            <div class="card">
                <h4 class="card-header">Sign Up</h4>
                <div class="card-body">
                    <div class="text-center">
                        <img class="" src="{% static 'images/signup.png' %}">
                    </div>
                    <form class="mt-3" action="{% url 'accounts:pn_reg_accounts' %}" method="POST" enctype="multipart/form-data">
                        {% csrf_token %}
                        <!--input의 name 속성은 view에서 정의한 것과 일치하도록-->
                        <div class="form-group">
                            <input type="email" class="form-control" id="email" name="email" placeholder="이메일 주소">
                        </div>
                        <div class="form-group">
                            <input type="text" class="form-control" id="name" name="name" placeholder="성명">
                        </div>
                        <div class="form-group">
                            <input type="text" class="form-control" id="user_id" name="user_id" placeholder="사용자 이름">
                        </div>
                        <div class="form-group">
                            <input type="password" class="form-control" id="user_pw" name="user_pw" placeholder="비밀번호">
                        </div>
                        <button type="submit" class="btn btn-primary">가입하기</button>
                    </form>
                </div>
            </div>

            <!--view에서 messages 프레임워크를 활용해 정의한 messages 적용-->
            {% if messages %}
                <div >
                    {% for message in messages %}
                        {{ message.tags }}! {{ message.message }}
                    {% endfor %}
                </div>
            {% endif %}

            <div class="card mt-2">
                <div class="text-center mt-3">
                    <p>이미 계정이 있으신가요? <a href="{% url 'accounts:pn_login' %}">로그인</a></p>
                </div>
            </div>
        </div>
    </div>
</div>
{% endblock body %}
댓글