웹 개발 시 필수 기능인 인증 기능은 일반적으로 로그인 시 username/password를 인증하는 것 외에도 로그인한 사용자에 대한 권한 부여와 웹 요청에 따른 사용자 식별, 사용자별 세션 할당 및 관리 기능 등 세션 처리 기능까지 포함된다.
장고에서 제공하는 User 테이블을 기본으로 사용한다.
장고에서 제공하는 인증 기능은 URL과 뷰는 이미 개발되어 있고, 템플릿은 템플릿 파일명만 정해져 있으므로 그 템플릿 내용은 개발자가 코딩해야 한다.
다만 회원가입 기능은 장고에서 제공하지 않으므로 직접 코딩해준다.
아래 2개는 직접 개발해야 한다.
setitng.py 파일에 지정해야 하는 항목 3가지
LOGIN_URL: 로그인이 필요해서 로그인 페이지로 리다이렉트시키고자 할 때 사용하는 URL로 login_required() 데코레이터를 사용해야 한다.
default: /accounts/login/
LOGIN_REDIRECT_URL: 장고의 LoginView 뷰는 로그인 처리가 성공한 후 next 파라미터로 지정한 URL로 리다이렉트 시킨다. next 파라미터가 지정되지 않으면 이 설정 항목에서 지정한 URL로 리다이렉트 시킨다.
default: /accounts/profile/
LOGOUT_REDIRECT_URL: 장고의 LogoutView 뷰는 로그아웃 처리가 성공한 후 next_page 속성으로 지정한 URL로 리다이렉트 시킨다. 없다면 이 설정 항목에서 지정한 URL로 리다이렉트 시킨다. 요청에 next 파라미터가 있으면 next에 지정한 URL이 next_page 속성으로 사용된다.
위 3가지 중 LOGIN_URL은 디폴트 값을 사용할 것이고, LOGOUT_REDIRECT_URL은 사용하지 않아도 되니까 LOGIN_REDIRECT_URL만 지정해준다.
LOGIN_REDIRECT_URL = '/'
또 폼을 장식하는 데 유용한 django-widget-tweaks 앱을 설치하고 등록한다.
설치
pip install django-widget-tweaks
settings.py 등록
'widget_tweaks',
인증 기능에 필요한 테이블은 장고에서 기본 제공하므로 코딩할 필요가 없다.
인증에 필요한 URL은 장고에서 기본으로 제공하기 때문에 django.contrib.auth.urls 모듈을 include() 함수로 가져와서 사용하면 된다.
BookMarkApp/urls.py
# 장고의 인증 URLconf를 가져와서 사용한다.
path('accounts/', include('django.contrib.auth.urls')),
path('accounts/register/', UserCreateView.as_view(), name='register'),
path('accounts/register/done/', UserCreateDoneTV.as_view(), name='register_done'),
LoginView 등 장고 auth 모듈에서 제공하는 뷰는 따로 코딩할 필요가 없고 가입 처리용 뷰 UserCreateView와 UserCreateDoneTV만 코딩해주면 된다.
BookMarkApp/views.py
base.html에서 우상단 Username 영역을 수정해준다.
{{ next }} 변수는 /accounts/login/?next=/post/3/ 처럼 로그인 URL의 쿼리 문자열로 지정된다. 만일 URL에 next 쿼리 문자열이 없으면, settigns.LOGIN_REDIRECT_URL 항목에 지정된 URL이 사용되고, 이 항목도 지정되어 있지 않으면 디폴트로 /accounts/profile/ URL로 리다이렉트된다.
가입 화면, 즉 사용자 계정을 생성하는 화면을 보여준다.
{% extends 'base.html' %}
{% load widget_tweaks %}
{% block title %}register.html{% endblock %}
{% block content %}
<h1>New User Registration</h1>
<p class="font-italic">Please enter your username and password twice.</p>
{% if form.errors %}
<div class="alert alert-danger">
<div class="font-weight-bold">Wrong! Please correct the error(s) below.</div>
{{ form.errors }}
</div>
{% endif %}
<form action="." method="post" class="card pt-3">
{% csrf_token %}
<div class="form-group row">
{{ form.username|add_label_class:"col-form-label col-sm-2 ml-3 font-weight-bold" }}
<div class="col-sm-5">
{{ form.username|add_class:"form-control"|attr:"autofocus" }}
</div>
</div>
<div class="form-group row">
{{ form.password1|add_label_class:"col-form-label col-sm-2 ml-3 font-weight-bold" }}
<div class="col-sm-5">
{{ form.password1|add_class:"form-control" }}
</div>
</div>
<div class="form-group row">
{{ form.password2|add_label_class:"col-form-label col-sm-2 ml-3 font-weight-bold" }}
<div class="col-sm-5">
{{ form.password2|add_class:"form-control" }}
</div>
</div>
<div class="form-group">
<div class="offset-sm-2 col-sm-5">
<input type="submit" value="Register" class="btn btn-info"/>
</div>
</div>
</form>
{% endblock %}
사용자 계정을 생성하기 위해 비밀번호를 두 번 입력할 수 있도록 password1 및 password2 입력 요소가 있다는 점 정도만 빼면 login.html과 거의 같다.
한가지 중요한 차이점은 login.html 파일에서는 AuthenticationForm을 사용했지만 이번 register.html 파일의 form 변수는 UserCreationForm 객체라는 점이다. UserCreationForm 폼도 장고에서 기본으로 제공한다.
템플릿 파일에서 장고의 폼을 장식하려 할 때 django-widget-tweaks 앱을 사용하면 HTML 태그의 요소들을 직접 다룰 수 있어서 편리하다.
가입 처리가 성공한 후에 보여주는 화면
{% extends 'base.html' %}
{% block title %}register_done.html{% endblock %}
{% block content %}
<h1>Registration Completed Successfully</h1>
<br>
<p>Thank you for registering.</p>
<p class="font-italic"><a href="{% url 'login' %}">Log in again</a></p>
{% endblock %}
비밀번호를 변경하기 위한 화면
{% extends 'base.html' %}
{% load widget_tweaks%}
{% block title %}password_change_form.html{% endblock %}
{% block content %}
<h1>{{ title }}</h1>
<p class="font-italic">Please enter your old password for security's sake,
and then enter your new password twice.</p>
{% if form.errors %}
<div class="alert alert-danger">
<div class="font-weight-bold">Wrong! Please correct the error(s) below.</div>
{{ form.errors }}
</div>
{% endif %}
<form action="." method="post" class="card pt-3">
{% csrf_token %}
<div class="form-group row">
{{ form.old_password|add_label_class:"col-form-label col-sm-2 ml-3 font-weight-bold" }}
<div class="col-sm-5">
{{ form.old_password|add_class:"form-control"|attr:"autofocus" }}
</div>
</div>
<div class="form-group row">
{{ form.new_password1|add_label_class:"col-form-label col-sm-2 ml-3 font-weight-bold" }}
<div class="col-sm-5">
{{ form.new_password1|add_class:"form-control" }}
</div>
</div>
<div class="form-group row">
{{ form.new_password2|add_label_class:"col-form-label col-sm-2 ml-3 font-weight-bold" }}
<div class="col-sm-5">
{{ form.new_password2|add_class:"form-control" }}
</div>
</div>
<div class="form-group">
<div class="offset-sm-2 col-sm-5">
<input type="submit" value="Password change" class="btn btn-info"/>
</div>
</div>
</form>
{% endblock %}
비밀번호 변경 처리가 성공한 후에 보여주는 화면
{% extends 'base.html' %}
{% block title %}password_change_done.html{% endblock %}
{% block content %}
<h1>{{ title }}</h1>
<br>
<p>Your password was changed</p>
{% endblock %}
로그아웃 처리가 성공한 후 나타나는 화면
{% extends 'base.html' %}
{% block title %}logged_out.html{% endblock %}
{% block content %}
<h1>Logged out</h1>
<br>
<div>
<i class="fas fa-quote-left"></i>
<span class="h6"> Thanks for spending
your quality time with this web site today. </span>
<i class="fas fa-quote-right"></i>
</div>
<p class="font-italic"><a href="{% url 'login' %}">Log in again</a></p>
{% endblock %}
출처: Django로 배우는 파이썬 웹 프로그래밍(실전편) - 김석훈님