티스토리 뷰

반응형

0.들어가면서

회원가입 로직을 구성하려면 어떻게 해야할까?? 비밀번호가 일치하는가? 안하면 돌아가자. 그리고 나머지 valid를 점검하자.(패턴은 단순한가? username이 중복되지 않는가?) valid하지 않으면 돌아가자. 둘다 맞으면 저장을 하면된다.

  • User.objects.create_user(username, email=None, password=None)   create_user 메서드를 사용하여 암호화 되어 저장을 시킨다.
  • User.set_password(password) 를 홍해 비번을 암호화 하면서 변경한다.

1. 사용자는 로그인 한 사람인가?

우리는 어떠한 page로 가더라도 login 한 것을 알고 있게 구현을 해야한다. 그럴 려면 우선은 웹은 통신을 HTTP로 한다는 점을 알아야 한다. HTTP는 요청(Resquest)과 응답(Response)로 구현한다. 이때 HTTP는 두가 특징을 가진다.

 

1-1 HTTP의 특징(stateless & Connectless)

HTTP의 특징은 상태가 없고 연결되지 않는다. 즉, 응답을 던져주고 연결이 끊어진다. 연겨이 끊기니 어떤 상태인지 알 수 없다. 여기서 우리는 질문을 할 수 있을 것이다. 왜 장바구니에 담겨있는건 연결이 끊어졌는데도 유지가 될까? 그 이유는 바로 쿠키 때문이다.

 

2. 쿠키

크롬 url 옆에 자물세를 눌러 보면 쿠키 보기가 가능하다.

우리가 쿠팡에서 쇼핑을 하고 있다고 예를 들어보자. 사용자는 장바구니에 물건을 담고 싶다고 쿠팡 서버에 보낸다. 그러면 쿠팡은 쿠키안에 장보구니의 정보를 넣어서 사용자에게 보낸다. 그렇게 되면 크롬 브라우저에 쿠키가 담기는 것이다. 만약 쿠키들을 지운다면 장바구니에 담긴 내용은 사라진다. 하지만, 2000년 초반까지도 쿠키 정보가 암호화 되어 있지 않아서 해킹에 취약했다. 그래서 생겨난 것이 세션이다.

+ 크롬의 시크릿모드는 창을 끄는 순간 쿠키가 지워진다.

 

 

3.세션

장고 내부에 특정 값을 저장 해서 쿠키요청하는 사람과 비교함으로 보안을 높였다. 저장, 만료시기 같은 것들이 DB나 메모리에 저장되어 있게 만든 것이다. 즉, 쿠키랑 비슷하지만, login같은 것들을 할 때는 쿠키가 아니라 세션에 저장을 해서 검증을 한번 더 하는 것이다.

 

보안적 측면에서 보면 쿠키보다 세션이 더 좋은 것이라는 것을 알 수 있다. 근데 왜 다 세션으로 안 하고 쿠키를 쓸까? COST(비용) 때문이다. 세션은 DB나 메모리에 저장이 되어 있기 때문에 세션은 서버의 리소스를 쓴다. 따라서 용량을 많이 차지하게 되면 비용이 증가하고 속도가 내려간다.

 

 

쿠키 세션 캐쉬(Cache)정리

요청 시 내가 누군지를 쿠키에 담아서 보내고 응답 시 추가 정보를 쿠키에 단아서 돌려준다. 그리고 쿠키 자체가 오염도어 있는 경우가 있기 때문에 100%확신이 불가능하다. 따라서 검증을 위해, 만료기간이나 키를 담아두는 세션이 필요한 것이다.

Cache(캐쉬) : 사용자가 한 번 방문한, 사이트를 다시 방문 시 좀 더 빠르게 방문이 가능하게 한다.(또 다른 저장소에 저장). 먼가 로딩이 안되거나 옛날 사이트가 보이면 캐쉬를 지우고 다시 접근하면 된다. 크롬은 F12로 개발자 도구를 열고 application을 누르면 쿠키나 캐쉬 등을 볼 수 있다.

 

쿠키: 사용자 관련 정보를 담고 요청에 포함시켜 보낸다.

캐쉬: 브라우저에서 요청을 보낼 때 필요한 거지만 걸러서 요청을 한다.(ex. css, javascript의 변화가 없다면 내부에 저장한다.)

 

 

4. 로그인 확인 하기

장고에서 db.sqlite3을 더블 클릭하면 DB에 저장된 정보(DB에 저장)를 편하게 볼 수 있다. [table]django-session을 눌러보면, 로그인한 정보가 뜨는데, 그 안의 값으로 검증하여 그 사람이 맞나 확인한다.

로그인한다 =django-session의 table에 create를 한다.
로그아웃한다 =Delete를 한다.

Create와 Delete를 한다고 생각하자. 즉, modelform의 흐름과 동일하다.

 

 

 

5. login 코드(AuthenticationForm)

urls.p y

app_name = 'accounts'

urlpatterns = [

    path('signup/', views.signup, name='signup'),

    path('login/', views.login, name='login'),

    path('<int:pk>/', views.detail, name='detail'),

]

 

login.html

{% extends 'base.html' %}

{% block body %}

    <form action="" method="POST">

        {% csrf_token %}

        {{ form.as_p }}

        <button>로그인</button>

    </form>

{% endblock %}

 

login.html +bootstrap

{% extends 'base.html' %}

{% load bootstrap4 %}

{% block body %}

    <form action="" method="POST">

        {% csrf_token %}

        {% bootstrap_form form %}

        <button class="btn btn-primary">로그인</button>

        <a href="{% url 'accounts:signup' %}">회원가입</a>

    </form>

{% endblock %}

 

 

base.html

<body>

    <p>{{ user.username }}</p>

    <div class="container">

        {% block body %}

        {% endblock %}

로그인 시 아이디가 뜨고 로그아웃 시 아이디가 안보인다. 하지만, 로그인 하면 로그인 버튼과 화원가입 버튼이 사라지도록 분기할 필요가 있어 보인다. 아래 처럼 하면 된다.

 

base.html +분기

<body>

    {% if user.is_authenticated %}

        <p>{{ user.username }}, 님 환영합니다.</p>

        <a href="{% url 'accounts:logout' %}">로그아웃</a>

    {% else %}

        <a href="{% url 'accounts:login' %}">로그인</a>

        <a href="{% url 'accounts:signup' %}">회원가입</a>

    {% endif %}

    <div class="container">

        {% block body %}

        {% endblock %}

 

 

{% if user.is_authenticated %}

settings.py - templates - options부분에 설정 된것이 context를 처리할 때 다음 3가지를 자동으로 쓸 수 있게 해놨다. request, auth, messages. auth부분은 유저와 관련된 정보를 쓸 수 있게 만들어 논거다. 따라서 base.html에서 user.is_authenticated를 불러오는거 없이 쓸 수 있는 이유는 auth에 user가 포함이 되어있기 때문이다.

 

 

views.py

from django.contrib.auth import login as auth_login

from django.contrib.auth.forms import UserCreationForm, AuthenticationForm

def login(request):

    if request.method == 'POST':

        # 사용자가 보낸 값 -> form

        form = AuthenticationForm(request, request.POST)

        # 검증

        if form.is_valid():

            # 검증 완료시 로그인!

            auth_login(request, form.get_user())

            return redirect('articles:index')

    else:

        form = AuthenticationForm()

    context = {

        'form': form

    }

    return render(request, 'accounts/login.html', context)

 

코드해석

ModelForm   => ArticleForm은 Article(모델)을 create하기 위한 Form
ModelForm   => UserCreationForm은 User(모델)을 create하기 위한 Form
Form           => AuthenticationForm은 모델과 관련이 없다. 일반 Form

+ github django에서 확인해 보면 class AuthenticationForm(forms.Form):에서 forms.Form보면 된다.

 

form = AuthenticationForm(request, request.POST)

AuthenticationForm은 모델폼이 아니라 일반 Form이다. 따라서 modelform이 아니기 때문에 모델에게 받는 정보가 없고 새로운 정보를 더 넘겨줘야 하기 때문에 request를 반드시 포함 시켜 줘야한다.

 

auth_login(request, form.get_user())

로그인 시 모델과 관련이 없고 로그인을 위한 함수가 존재한다. 그게 from django.contrib.auth import login as auth_login 으로 login 함수를 import 한거다. 이때, views에서 정의한 함수의 이름도 login이기 때문에 뒤에 as auth_login으로 이름을 바꿔서 적었다. 그리고 form.get_user()은 form에 있는 user정보이다. login 함수는 DB table에 세션을 저장하고 쿠키에 담아서 사용자에게 넘겨준다.

 

request를 넘겨준 이유는 로그인은 요청한 정보를 조작한다. 따라서 쿠키와 세션 중에 쿠키는 요청 객체에 담겨있기 때문에 쿠키를 받기위해서는 request를 필수로 넘겨 줘야한다.

 

 


 

 

로그인이 되어 있다면 로그인 페이지로 못 들어오게 만들자.

views.py 추가

def login(request):

    if request.user.is_authenticated:

        return redirect('articles:index')

    if request.method == 'POST':

        # 사용자가 보낸 값 -> form

        form = AuthenticationForm(request, request.POST)

        # 검증

        if form.is_valid():

            # 검증 완료시 로그인!

            auth_login(request, form.get_user())

            return redirect('articles:index')

    else:

        form = AuthenticationForm()

    context = {

        'form': form

    }

    return render(request, 'accounts/login.html', context)

 

들어가지 않게 하기 위해서 html에서 링크를 표현하지 않아도 되지만, 내부 장고 코드에서도 반영해 줘야한다.

templates에서는 settings.py의 설정에 의해 user를 그냥 써도 되지만, views에서는 request에서 user를 가져와야한다.

 

 


원래페이지로 이동하기

로그인이 되어있지 않아 글 작성, 로그아웃 시에 @login_required를 써서 login창으로 넘어온경 후 로그인 후에 원래 가려고 했던 곳으로 이동을 시키는 코드를 알아보자.

로그인을 안하고 글을 쓰면 @login_required를 통해 로그인 창으로 자동으로 이동한다. 이때, url을 보면 로그인 성공 시 가게될 url도 '?next=/~/'로 적혀있다. 그렇다면 url의 next에 적힌 것처럼 구현이 되게 하려면 어떻게 해야할까?

로그인 창에서 로그인을 누르면 POST요청으로 login으로 들어온다. 그 후에 검증이 완료된 이후에 return redirect 쪽에 특정 정보를 담거나 수정을 해줘야한다.

+ url의 ? 뒤에 어떠한 parameter가 되는 것은 request.POST 이다.

+ 단축평가. 굵은 글씨가 리턴값

T or T

F or T

T or F

F or F

 

 

def login(request):

    if request.user.is_authenticated:

        return redirect('articles:index')

    if request.method == 'POST':

        # 사용자가 보낸 값 -> form

        form = AuthenticationForm(request, request.POST)

        # 검증

        if form.is_valid():

            # 검증 완료시 로그인!

            auth_login(request, form.get_user())

            return redirect(request.GET.get('next') or 'articles:index')

    else:

        form = AuthenticationForm()

    context = {

        'form': form

    }

    return render(request, 'accounts/login.html', context)

 

python 의 단축평가를 적용해서 next 파라메터를 받아서 오는 애들이 있으면 받아온 곳으로 보내고 없으면 'article:index'로 보낸다.

 

@login_required는 로그인 창으로 가게한다. 로그인 후에 next 파라미터를 활용하여 url를 적어주면 처음 가고자 한곳으로 되돌아 간다.

 

 

 

 

 

대망의 로그아웃에 대해 구현해 보자.

 

han-py.tistory.com/149

 

[Django]사용자인증관리_logout

로그아웃은 간단하다. urls.py urlpatterns = [     path('signup/', views.signup, name='signup'),     path('login/', views.login, name='login'),     path('logout/', views.logout, na..

han-py.tistory.com

 

 

반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함