"회원관리 3-0. 로그인 & 로그아웃"의 두 판 사이의 차이

Pywiki
둘러보기로 가기 검색하러 가기
잔글 (Sam님이 회원관리 3. 로그인 문서를 회원관리 5. 로그인 문서로 이동했습니다)
잔글 (Sam님이 회원관리 5. 로그인 문서를 회원관리 4. 로그인 문서로 이동했습니다)

2021년 6월 21일 (월) 14:05 판


유저들의 권한, 정보에 관한 것들.


1 URL작성

필요한 기능에 대해 생각하고 url을 짠다.

from django.urls import path
from django.contrib.auth import views as auth_views#장고에서 제공하는 기능 활용!

app_name = 'membership'

urlpatterns = [
    path('login/', auth_views.LoginView.as_view(template_name='login.html'), name='login'),
    path('logout/', auth_views.LogoutView.as_view(), name='logout'),
]

심지어 뷰를 안만들어도 된다.

  • registration/login.html 을 기본옵션으로 하지만, 따로 디렉터리를 만드는 것은 낭비다. 때문에 template_name 변수를 따로 지정했다.
  • 로그아웃 뷰에선 기본 탬플릿이 없지만, template_name을 지정하면 로그아웃 후 redirect할 탬플릿을 지정할 수 있다.

2 네비게이션 바에 로그인 버튼 만들기

네비게이션 바 html 적당한 곳에 다음을 삽입한다.

<!--로그인, 로그아웃 기능-->
{% if user.is_authenticated %}
    <p>{{ user.username }}</p><a class="nav-link" href="{% url 'membership:logout' %}">(로그아웃)</a>
{% else %}
    <a class="nav-link" href="{% url 'membership:login' %}">로그인</a>
{% endif %}

user의 속성을 이용해 로그인 상태일 때와 아닐 때의 형식이 다르게 만들었다.

3 탬플릿 만들기

3.1 login.html

{% extends "연결할.html" %}

{% block content %}
<div class="container">
    <form method="post" action="{% url 'membership:login' %}">
        {% csrf_token %}
<!-------------------------------------- 입력에 에러가 났을 때 불러올 html-->
        {% include "form_errors.html" %}
<!-------------------------------------- 입력을 위한 공간-->
        <div class="form-group">
            <label for="username">ID</label>
            <input type="text" class="form-control" name="username" id="username"
                   value="{{ form.username.value|default_if_none:'' }}">
        </div>
        <div class="form-group">
            <label for="password">비밀번호</label>
            <input type="password" class="form-control" name="password" id="password"
                   value="{{ form.password.value|default_if_none:'' }}">
        </div>
        <button type="submit" class="btn btn-primary">로그인</button>
    </form>
</div>
{% endblock %}

3.2 form_errors.html

membership 앱과 관련한 모든 에러메시지를 관리하기 위해 에러메시지만 띄우는 탬플릿을 만든다. 일괄적, 일관적으로 모든 공간에 적용할 수 있게끔.

에러가 발생했을 때 에러메시지를 띄울 html을 불러온다.

{% if form.errors %}
    {% for field in form %}
<!------------------------- 필드 오류를 출력 -->
        {% for error in field.errors %}  
            <div class="alert alert-danger">
                <strong>{{ field.label }}</strong>
                {{ error }}
            </div>
        {% endfor %}
    {% endfor %}
 <!----------------------- 넌필드 오류를 출력 -->
    {% for error in form.non_field_errors %}  
        <div class="alert alert-danger">
            <strong>{{ error }}</strong>
        </div>
    {% endfor %}
{% endif %}

필드오류 : 사용자가 form 양식에 맞지 않는 데이터를 입력했을 때.

넌필드오류 : 기타 등등 에러

4 로그인, 로그아웃 성공 후 이동할 url 만들기

4.1 로그인 url

일반적으로 @login_required(login_url='membership:login') 형태로 로그인 url을 써주어야 하지만, 모든 함수에 이걸 써넣긴 어렵고, 수정에도 불편하다.

=> settings.py에 LOGIN_URL = 'membership:login' 형태로 변수를 지정하면 데코레이터의 괄호에 무언가를 써주지 않아도 잘 기능한다.

4.2 로그인 로그아웃 후 리다이렉트

settings.py에서 새로운 설정항목을 만들어주어야 한다.

관련변수 설명 예시
LOGIN_REDIRECT_URL 로그인 후 연결될 주소 설정.

next 변수를 주어 보던 페이지로 이동하게 할 수도 있다.(다음 내용 참고)

주소 대신 '앱이름:list' 형태의 인덱스도 가능하다.

LOGIN_REDIRECT_URL = '/'
LOGOUT_REDIRECT_URL 로그아웃 후 연결될 주소 설정. LOGOUT_REDIRECT_URL = '/'

4.3 보던 페이지로 돌아가기

그런데, 사실 로그인 후에 보던 페이지가 안나오면 다시 찾아들어가야 하고.. 불편하다; 다행스럽게도 로그인 기능을 제대로 구현해두면 로그인 페이지로 넘어갈 때 링크가 http://127.0.0.1:8000/membership/login/?next=/보고있던페이지/ 형태로 구성된다. 이전 페이지에 대한 정보를 담고 있는데, 로그인 탬플릿에 다음의 숨겨진 항목을 추가하면 된다.(폼 안에 추가해야 한다.)

<input type="hidden" name="next" value="{{ next }}">

submit은 해당 링크에 대한 정보를 그대로 form으로 보내기에 {{next}}에 있는 이전페이지 주소를 받아 기능한다. 로그인 함수에서 알아서 기능해준다.

[한 가지 의문인 것은... 이전페이지의 정보인 next를 어떻게 가져온거지;;? 이전페이지에서 보내준 것도 아닌데?? 아무래도 데코레이터에 걸리는 듯하다.

데코레이터에 걸려서 로그인화면으로 넘어가면 next 인자가 생긴다.]

네비게이션바에 구현한 로그인 버튼은 next인자를 남기지 않는데, 로그인바의 버튼의 주소를.. herf="{% url '인덱스' %}"?next={{request.path}}" 로 넣어주면 현재 경로를 넘겨줄 수 있다.

5 권한

일반 view 사용 클래스형 view 사용
로그인이 필요한 기능 로그인이 필요한 기능(함수) 위에 @login_required를 추가한다.
from django.contrib.auth.decorators import login_required

@login_required(login_url='common:login')
def 함수이름(request):
    명령...
상속받을 클래스 이전에 첫 번째로 상속받게 한다.
from django.contrib.auth.mixins import LoginRequiredMixin

def 함수이름(LoginRequiredMixin, 상속받을 클래스):
    명령...

유저관련기능...

{% if user.is_authenticated %}

위 조건이 있으면 로그인 할 때만 실행된다.

일반 뷰에선 login_url로 로그인 페이지 지정이 가능하고, 클래스형 뷰에선 settins.py의

LOGIN_REDIRECT_URL = '/article/'

LOGIN_URL = '/user/login/'

따위를 지정하든가, login_url = settings.LOGIN_URL 변수를 오버라이딩 하면 된다.


@login_required와 Mixin은 내부적으로 requests.user.is_authenticated 값을 비교한다.

별도의 인증여부를 확인해야 하는 경우는 requests.user.is_authenticated를 그대로 가져다 쓰면 오류 없이 사용할 수 있다.


@login_required 는 클래스형 뷰에선 사용이 안된다.

클래스형 뷰엔 2가지 방식으로 적용할 수 있다.

LoginRequiredMixin을 상속하거나, @method_decorator(login_required, '메소드명') 형태로 클래스형 뷰 안의 메소드에 적용할 수 있다.


데코레이터.

데코레이터 파일을 만든 후,

def 데코레이터명(func):
    def decorated(request, *args, **kwargs):
        내용
        return func(request, *args, **kwargs)
    return decorated

import 해서 @method_decorator(데코레이터명, '메소드명') 형태로 적용할 수 있다.

적용할 데코레이터가 많으면 위에 리스트를 정의한 후, 데코레이터명 대신 리스트를 넣으면 리스트 안의 데코레이터를 한번에 적용할 수 있다.

6 로그인 관련

설명 코드
유저 인증 인증 정보를 객체에 담는다. from django.contrib.auth import authenticate

객체 = authenticate(username=name, password=password)

로그인 from django.contrib.auth import login

login(request, 위에서의객체)

로그아웃 from django.contrib.auth import logout

logout(request)