오늘 강의는 16강1과 16강2로 나누어 진행되었음을 알립니다.
로그인 페이지에서 회원가입 버튼 만들어 이동할 수 있도록 하기
<!-- signin.html -->
...
<!-- 장고의 특성 : name 지정해두면 바로 사용 가능 -->
<a href="{% url 'signup' %}">회원가입</a>
<button class="btn btn-info">로그인</button>
...
로그인 페이지와 회원가입 페이지 Style 통일
<!-- signin.html -->
<a
style="color: black; font-weight: bold;"
class="fs-5 text-decoration-none m-3"
href="{% url 'signup' %}">회원가입</a>
<a
style="color: black; font-weight: bold;"
class="fs-5 text-decoration-none">로그인</button>
요청 방식 4가지
# 값을 읽고 싶을 때 GET - URL PAREMETER(http://awdaw.com??title=안녕하세요)
# 값을 지우고 싶을 때 DELETE
# 값을 수정하고 싶을 때 PUT - body
# 값을 생성하고 싶을 때 POST
요청 테스트
from django.shortcuts import render, HttpResponse
# 로그인 함수
def signin(request)
if request.method == "GET":
print(request.GET['title'])
return render(request, 'page/signin.html')
...
로그인 로직 구성하기
# user > views.py
from django.contrib import messages
from django.shortcuts import render, redirect
from django.contrib.auth import authenticate, login
from django.contrib.auth.hashers import make_password
from user.models import User
# 로그인 함수
def signin(request):
if request.method == "GET":
return render(request, 'page/signin.html')
if request.method == "POST":
username=request.POST['username']
password=request.POST['password']
user = authenticate(username=username, password=password)
if user:
login(request, user)
return redirect('board')
else:
messages.error(request, "입력값을 확인해주세요.")
return redirect('signin')
# 회원가입 함수
def signup(request):
if request.method == "GET":
return render(request, 'page/signup.html')
<!-- signin.html -->
{% extends 'common/base.html' %}
{% block content %}
<div class="card">
<div class="card-body">
<form method="post" id="signin_form">
<div class="row text-center" style="margin-top: 10px">
<div class="col">
<label class="form-label">아이디</label>
<input class="form-control" name="username" id="username" type="text">
</div>
</div>
<div class="row text-center" style="margin-top: 10px">
<div class="col">
<label class="form-label">비밀번호</label>
<input class="form-control" name="password" id="password" type="password">
</div>
</div>
</form>
<div class="row text-end" style="margin-top: 10px">
<div class="col">
<a
style="color: black; font-weight: bold;"
class="fs-5 text-decoration-none m-3"
href="{% url 'signup' %}">회원가입</a>
<a
style="color: black; font-weight: bold;"
class="fs-5 text-decoration-none" id="sign_btn">로그인</button>
</div>
</div>
</div>
</div>
<script>
let sign_btn = document.getElementById("sign_btn");
let password = document.getElementById("password");
let username = document.getElementById("username");
let signin_form = document.getElementById("signin_form");
sign_btn.addEventListenner("click", ()=> {
if(!username.value){
alert("아이디를 입력해주세요.");
return false;
}
if(!password.value){
alert("비밀번호를 입력해주세요.");
return false;
}
signin_form.submit();
})
</script>
{% endblock %}
CSRF 에러 발생 → 토큰 발급 해줌.
...
<form method="post" id="signin_form">
{% csrf_token %}
<div class="row text-center" style="margin-top: 10px">
<div class="col">
---
로그인 시도
유효하지 않기 때문에 다시 리다이렉팅 완료됨.
{% extends 'common/base.html' %}
{% block content %}
{% for message in messages %}
<div>
{{ message }}
</div>
{% endfor %}
...
<div class="alert alert-primary" role="alert">
{{ message }}
</div>
{% endfor %}
<--! signup.html -->
{% extends 'common/base.html' %}
{% block content %}
<div class="card">
<div class="card-body">
<div class="row text-center" style="margin-top: 10px">
<div class="col-12">
<form method="post" id="sign_form">
{% csrf_token %}
<!-- 아이디 -->
<label class="form-label">아이디</label>
<input class="form-control" type="text" name="username" id="username">
<!-- 비밀번호 -->
<label class="form-label">비밀번호</label>
<input class="form-control" type="password" name="password" id="password">
<!-- 비밀번호 확인 -->
<label class="form-label">비밀번호 확인</label>
<input class="form-control" type="password" name="chk_password" id="chk_password">
<!-- 닉네임 -->
<label class="form-label">닉네임</label>
<input class="form-control" type="text" name="nickname" id="nickname">
</form>
</div>
<!-- 회원가입 버튼 -->
<div class="row text-end" style="margin-top: 10px">
<a class="fs-5 text-decoration-none m-3"
style="color: black; font-weight: bold; cursor: pointer"
id="sign_btn"
>회원가입</a>
</div>
</div>
</div>
</div>
<script>
let sign_btn = document.getElementById("sign_btn");
let sign_form = document.getElementById("sign_form");
let username = document.getElementById("username");
let password = document.getElementById("password");
let chk_password = document.getElementsById('chk_password');
let nickname = document.getElementById('nickname');
sign_btn.addEventListener("click", ()=>{
if(!username.value){
alert("아이디를 입력해주세요.");
return false;
}
if(!password.value){
alert("비밀번호를 입력해주세요.");
return false;
}
if(password.value !== chk_password.value){
alert("비밀번호를 확인 해주세요.");
return false;
}
if(!nickname.value){
alert("비밀번호를 입력해주세요.");
return false;
}
sign_form.submit();
})
</script>
{% endblock %}
로직 작성 + 비밀번호 암호화 진행
# user>views.py
from django.contrib import messages
from django.shortcuts import render, redirect
from django.contrib.auth import authenticate, login
from django.contrib.auth.hashers import make_password
from user.models import User
# 로그인 함수
def signin(request):
if request.method == "GET":
return render(request, 'page/signin.html')
if request.method == "POST":
username=request.POST['username']
password=request.POST['password']
user = authenticate(username=username, password=password)
if user:
login(request, user)
return redirect('board')
else:
messages.error(request, "입력값을 확인해주세요.")
return redirect('signin')
# 회원가입 함수
def signup(request):
if request.method == "GET":
return render(request, 'page/signup.html')
if request.method == "POST":
username=request.POST['username']
password=request.POST['password']
nickname=request.POST['nickname']
user = User.objects.filter(username=username)
# exists - 존재하면 True, 존재하지 않으면 False
if user.exists():
messages.error(request, "이미 가입한 아이디 입니다.")
return redirect('signup')
else:
new_user = User(
username=username,
password=make_password(password),
nickname=nickname,
)
new_user.save()
login(request, new_user)
return redirect('board')
오늘 강의는 앞서 만들었던 회원가입과 로그인 페이지의 로직에 해당하는 백엔드 작업을 해주었다.
먼저 오늘의 첫 강의에서는 ‘로그인 페이지’의 요청 방식과, JavaScript Click 이벤트를 이용해서 POST 요청을 받아온 아이디와 비밀번호의 유효성 검사를 하는 로직을 구성했다.
우선, 첫 강의에서는 미리 저장되어 있는 아이디와 비밀번호가 전혀 없는 상태이기 때문에 당연히 유효하지 않는 입력이라는 결과값을 보여주는 로직을 작성했다.
이 과정에서 addEventListener의 클릭 이벤트를 활용했는데, 예상과 달리 로그인을 클릭했을 때 다시 로그인 페이지로 리다이렉트되는 로직이 작동하지 않아서 애를 먹었다.
그런데 알고보니 Listener를 Listenner라고 오타를 내서 발생한 현상이었다. html 파일 안에서 script 태그를 사용할 때 오타를 잡아주지는 않기 때문에 예전에도 이 경우때문에 고생한 적이 많았었던 기억이 다시 살아났다..
그래도 얼른 해결하고 두번째 강의를 들으며 ‘회원가입 페이지’의 로직을 로그인 페이지의 로직을 활용해서 작성했다.
다만 회원가입이기 때문에 직접적인 password 값을 저장시켜야 하는데, 보안상 그대로 노출되면 위험하기 때문에 make_password라는 함수를 활용해 암호화를 해주었다.
그래서 기존의 1234라고 입력한 password를 DB에는 pbkdf2_sha256GIJpUd2Kolmnc5KAQckQUt$ncOeLcy4Pb3JDGaRoBGXfg+QazOWxkDT7bCemYwNlBQ= 와 같이 암호화가 완료된 형태로 저장이 되는 것을 확인했다.
오늘 강의를 통해 백엔드 로직을 구성했지만, 한가지 아쉬웠던 점은 강의 흐름이 빠르다보니 회원가입 페이지에 대한 작성은 강의를 멈춰서 일일이 확인하며 작성했던 점이다.
또한, 이 코드가 맞는지 여부를 확인할 수 있도록 강의에서 보여준 코드 전문을 첨부해줬으면 좋겠다. 복사-붙여넣기의 위험이 있으니 이미지 형태로 보여준다면 확인 용도로 용이하게 사용할 것 같다.
그래도 오늘 강의로 DB에 실제로 사용자 정보를 저장하는 기초적인 백엔드 로직을 간단히 구성할 수 있어 신기했다.
자주 사용하던 Springboot에서는 Spring Security를 이용해 회원 관리 로직을 작성했었는데, 이 강의를 통해 조금 더 프론트 성향이 강한 페이지를 만들게 되면서 여러가지 기존의 라이브러리를 가져와 간단하고 빠르게 구현하게 된 점이 신기하고 좋았으며, 프론트에게 API를 넘겨줄 때 더 고려해야할 점들에 대해서 고민해볼 수 있어 좋았다.