티스토리 뷰

1-1. 로그인 views.py ( 함수 버전 )

 

    - 로그인 뷰는 GET 방식과 POST 방식을 나눠서 진행하고, username, password 정보를 받는 것에 있어서 회원가입 뷰와 비슷하다. 추가되는 부분은 입력한 아이디가 존재하는 아이디인지, 비밀번호가 일치하는지 확인하는 부분이다. 

 

    - 로그인창에서 입력한 username과 똑같은 username 갖는 사용자를 가져와서 user에 저장한다. 여기서 사실은 아이디가 존재하지 않을 경우의 예외처리가 필요하지만 어떻게 하는지 까먹었다. (이것이 개발일지를 작성하는 이유.... ㅠ 아마 앞으로 있는 포스팅에 언급될 예정)

 

    - check_password 를 사용하여 입력한 비밀번호와 user에 저장된 비밀번호가 일치하는지 확인한다. 일치한다면, 세션 정보를 저장한다. 이것이 쿠키 정보가 된다.  

 

def login(request):
    if request.method == 'GET':
        return render(request, 'login.html')

    elif request.method == 'POST':
        username = request.POST.get('username', None)
        password = request.POST.get('password', None)
        errMsg = {}

        if not (username and password):
            errMsg['error'] = "모든 값을 입력하세요"
        else:
            user = Users.objects.get(username = username)
            if check_password(password, user.password):
                request.session['user'] = user.id
                return redirect('/')
            else:
                errMsg['error'] = "비밀번호를 다시 입력하세요"
        return render(request, 'login.html', errMsg)

 

1-2. 로그인 login.html ( 함수 버전 ) bootstrap

   

    - {% csrf_token %} : 이제 로그인 정보를 서버로 전달한다.  이 때, 다른 사이트에서 우리 서버로 전달하는 것(크로스 도메인)을 막기위한 보안장치가 된다. 암호화된 정보(토큰)을 저장한다.

 

    - inpyt type 을 "password" 로 설정하여 비밀번호를 입력할 때 ******* 와 같이 입력되게 한다.

 

    - id : views.py로 넘겨질 때, 어떤 아이디로 받을 것인지. 즉, 해당하는 필드 값의 id가 된다.

 

    - placeholder :  아래와 같이 사용자가 아무런 값도 입력하지 않았을 때에 어떤 형태로 있을 것인지 나타낸다.  

{% extends 'base.html' %}
{% block contents %}

<div class = "row mt-5">
    <div class = "col-12 text-center">
        <h1>로그인</h1>
    </div>
</div>

<div class = "row mt-5">
    <div class = "col-12">
        {{ error }}
    </div>
</div>    

<div class = "row mt-5">
    <div class = "col-12">
        <form method = "POST" action=".">
            {% csrf_token %}
            <div class="form-group">
                <label for="username">사용자 이름</label>
                <input type="text" class="form-control" id="username" placeholder ="사용자 이름" name = "username">
            </div>
                            
            <div class="form-group">
                <label for="password">비밀번호</label>
                <input type="password" class="form-control" id="password" placeholder = "비밀번호" name = "password">
            </div>

            <button type="submit" class="btn btn-primary">로그인</button>
        </form>
    </div>
</div>

{% endblock %}

 

 

 


 

 

2-1. 로그인 forms.py

 

    - django에서는 form 형식을 제공한다. 로그인 폼에 필요한 아이디와 비밀번호 필드를 정의한다. 해당 필드값이 입력되지 않았을 경우의 에러 메세지를 설정할 수 있고 최대 길이, 라벨 등을 설정할 수 있다.

 

    - 위에서는 input type = "password" 로 설정했다면, form에서는 widget 을 forms.PasswordInput으로 설정하여 비밀번호가 *****와 같이 입력되도록 한다. 

 

    - clean() 메소드를 사용하여 입력한 두 값을 유효성과 인증을 검사한다.  메소드 이름처럼 데이터가 유효한지 확인하는 기능을 하며 딕셔너리 형태를 갖는다.

 

    - username, password 가 인증과 유효성 검사를 거치고 나면, 두 개의 값 모두 입력되었는지 확인한다. 이후에, DB에 존재하는 아이디인지 확인하기 위해 objects.get (username = username) 코드를 시도한다. 만약 시도했는데 존재하지 않는 아이디인 경우에는 경고문을 저장하고 되돌아간다. 존재하는 아이디로 확인되면 비밀번호 일치 검사를 한다. 일치할 경우에 사용자의 고유 아이디를 저장한다.

    

from django import forms
from .models import Users
from django.contrib.auth.hashers import check_password

class LoginForm(forms.Form):
    username = forms.CharField(error_messages={"required" : "아이디를 입력해주세요"}, max_length=32, label = "사용자 이름")
    password = forms.CharField(error_messages={"required" : "비밀번호를 입력해주세요."}, 
    			max_length= 64, label = "비밀번호", widget=forms.PasswordInput)

    def clean(self):
        cleaned_data = super().clean()
        username = cleaned_data.get('username')
        password = cleaned_data.get('password')

        if password and username :
            try:
                user = Users.objects.get(username = username)
            except Users.DoesNotExist:
                self.add_error("username", "아이디가 존재하지 않습니다.")
                return

            if not check_password(password, user.password):
                self.add_error("password", "비밀번호가 일치하지 않습니다.")
            else:
                self.user_id = user.id

 

2-2. 로그인 views.py ( forms 버전 )

 

    - GET(그냥 페이지에 접속한 경우)일 때는 그냥 위에서 만든 LoginForm을 불러온다.

 

    - POST(사용자가 form 작성이 끝난 경우)일 때는, form에 입력한 필드값과 에러메세지를 저장하고  is_valid()를 사용하여 입력한 폼의 값이 유효한지 확인한다.

 

    - 폼 값이 올바르다면 사용자 고유 아이디를 세션 정보에 저장하고 홈화면으로 돌아간다. 반대로 폼이 유효하지 않을 경우에는 form에 저장된 에러 메세지를 login.html 으로 전달해서 화면에 표시될 수 있도록 한다. login.html에서 전달받은 form은 form이라는 변수로 사용된다. 만약에 errorMessage라는 변수로 사용하고 싶으면 {'errorMessage' : form} 이라고 하면 된다.

 

def login(request):
    if request.method == 'GET':
        form = LoginForm()
    elif request.method == "POST":
        form = LoginForm(request.POST)
        if form.is_valid():
            request.session['user'] = form.user_id
            return redirect('/')

    return render(request, 'login.html', {'form' : form})

 

 

2-3. 로그인 login.html

 

    - forms.py에서 입력한 필드값 각각의 label, input type에 맞춰서 화면에 나타낸다.  만약 같이 전달받은 에러메세지가 있다면, 해당하는 필드 아래에 표시한다.

{% extends 'base.html' %}
{% block contents %}

<div class = "row mt-5">
    <div class = "col-12 text-center">
        <h1>로그인</h1>
    </div>
</div>

<div class = "row mt-5">
    <div class = "col-12">
        <form method = "POST" action=".">
            {% csrf_token %}

            {% for field in form %}
            <div class ="form-group">
                <label for = "{{ field.id_for_label }}">{{field.label}}</label>
                <input type = "{{ field.field.widget.input_type }}" class ="form-control" id ="{{field.id_for_label}}" 
                placeholder = "{{field.label}}" name = "{{field.name}}">
            </div>
            {% if field.errors %}
            <span style = "color:red">{{field.errors}}</span>
            {% endif %}
            {% endfor %}

            <button type="submit" class="btn btn-primary">로그인</button>
        </form>
    </div>
</div>

{% endblock %}

  

각각의 오류에 대해서 에러메세지가 제대로 나오는 것을 알 수 있다.

 

(1) 비밀번호를 다르게 입력한 경우

 

(2) 존재하지 않는 아이디인 경우

 

(3) 아이디를 입력하지 않은 경우

 

(4) 비밀번호를 입력하지 않은 경우

 

 

 

로그인 후에, 세션 정보 ( 쿠키 )

처음 sessionId를 배울 때는, F12 -> Application 메뉴에서 Cookies sessionid를 확인해보는 것이 좋다.

로그인 후에는 나의 세션 아이디가 저장된 것을 알 수 있다.

 

쿠키 세션 차이점, 세션아이디가 헷갈리는데, 아래 페이지에서 설명 잘해주셨다... 담에 또 봐야지

 

Cookies 쿠키는 사용자의 아이디와 비밀번호 같은 것을 사용자의 로컬컴퓨터의 파일이나 메모리에 저장하는 작은 파일이다.  그러니까 사용자의 로컬 컴퓨터에 정보를 저장했다가 참고한다. (자동 로그인, 팝업, 장바구니 등 ..)

 

session 세션은 웹 버에 접속하여 브라우저를 종료할 때까지 같은 상태를 유지되는 상태를 뜻한다. ( 로그인 정보 유지)

  쿠키 세션
보안 보안에 취약 비교적 좋음
속도 빠름 느림
라이프 사이클 삭제할 때까지 유지 브라우저 종료할 때 까지
저장 위치 파일로 저장 서버에 저장

 

https://jeong-pro.tistory.com/80

 

Web - 쿠키와 세션의 차이, 용도, 사용법(cookie,session)

웹에서 쿠키와 세션 (Cookie & Session) 쿠키와 세션을 사용하는 이유 HTTP 프로토콜의 특징이자 약점을 보완하기 위해서 사용한다. HTTP 프로토콜의 특징 1) 비연결지향(Connectionless) HTTP는 먼저 클라이언트..

jeong-pro.tistory.com

 

 


 

 

 

3. 로그아웃 views.py

    - 로그아웃할 때에는 어떤 html 파일도 필요없고 그냥 사용자 아이디를 저장한 세션 정보만 삭제하면 된다. 

def logout(request):
    if request.session.get('user'):
        del(request.session['user'])
    return redirect('/')

 

 

 


 

 

4. 홈화면 index.html

 

    - 이제는 로그인, 로그아웃에 성공한 경우 홈화면으로 이동할 수 있도록, 홈화면을 만들어야 한다. 홈 화면에는 로그인, 로그아웃, 회원가입, 게시물 보기, 게시물 쓰기  다섯 개의 메뉴가 들어가야한다. 이 때, 로그인된 상태에서는 로그아웃 메뉴만 나타나고, 로그아웃된 상태에서는 로그인, 회원가입 메뉴만 나타나야 한다. 이 조건을 만족하도록 홈화면을 꾸며야한다.

 

    - 로그인 여부는 세션에 사용자 아이디가 저장되어있는지로 알 수 있다. request.session.user 에 값이 있으면 로그아웃만 되도록 한다. 그게아니라면 else 문에 따라서, 로그인과 회원가입 메뉴만 나타나도록 한다. 

 

    - onclick = "location.href='url주소'" 를 사용하여 메뉴를 클릭했을 때, 해당하는 url 주소로 이동하도록 한다.

 

{% extends "base.html" %}
{% block contents %}
<div class = "row mt-5">
    <div class = "col-12 text-center">
        <h1>홈페이지</h1>
    </div>
</div>

<div class = "row mt-5">
    {% if request.session.user %}
        <div class = "col-3">
            <button class ="btn btn-primary btn-block" onclick = "location.href ='/users/logout/'">로그아웃</button>
        </div>

    {% else %}
        <div class = "col-3">
            <button class ="btn btn-primary btn-block" onclick = "location.href ='/users/login/'">로그인</button>
        </div>
        <div class = "col-3">
            <button class ="btn btn-primary btn-block" onclick = "location.href ='/users/register/'">회원가입</button>
        </div>
    {% endif %}
</div>
<div class = "row mt-5">
    <div class = "col-3">
        <button class ="btn btn-primary btn-block" onclick = "location.href ='/board/list/'">게시물 보기</button>
    </div>
    <div class = "col-3">
        <button class ="btn btn-primary btn-block" onclick = "location.href ='/board/write/'">게시물 쓰기</button>
    </div>
</div>

{% endblock %}

 

 

댓글