Доработки системы авторизации и добавление сессий
В этом шаге давайте доработаем систему добавив опцию «Запомнить меня» используя сессии и cookie.
Здесь снова нам не нужно изобретать велосипед благодаря встроенной системе аутентификации Django. Мы можем построить нашу систему аутентификации, расширив ее и настроив в соответствии с нашими потребностями.
В нашем блоге Django использует эту аутентификацию в своем модуле django.contrib.auth, конфигурация которого уже включена в settings.py, когда мы создавали нашу авторизацию в прошлом модуле.
Начнем с формы входа. В Django есть встроенный AuthenticationForm базовый класс для аутентификации пользователей на основе имени пользователя и пароля.
Мы создадим наш логин, расширив его, чтобы добавить флажок «Запомнить меня», а также загрузим поля имени пользователя и пароля с помощью виджетов, как мы видели в предыдущих шагах.
Опция «Запомнить меня» — это хорошая функция, поскольку пользователи не хотят вводить учетные данные каждый раз, когда посещают сайт.
Давайте в наши forms.py добавим форму авторизации:
from django.contrib.auth.forms import UserCreationForm, AuthenticationForm
class LoginForm(AuthenticationForm):
username = forms.CharField(max_length=100,
required=True,
widget=forms.TextInput(attrs={'placeholder': 'Username'}))
password = forms.CharField(max_length=50,
required=True,
widget=forms.PasswordInput(attrs={'placeholder': 'Password'}))
remember_me = forms.BooleanField(required=False)
class Meta:
model = User
fields = ['username', 'password', 'remember_me']
Далее давайте настроим представление для использования созданной нами формы входа. В Django также есть встроенный LoginView. Мы можем переопределить некоторые атрибуты и методы класса в соответствии с нашими потребностями.
В views.py добавим новый класс:
from django.contrib.auth.views import LoginView
from .forms import SignUpForm, LoginForm
class CustomLoginView(LoginView):
form_class = LoginForm
def form_valid(self, form):
remember_me = form.cleaned_data.get('remember_me')
if not remember_me:
# Установим время истечения сеанса равным 0 секундам. Таким образом, он автоматически закроет сеанс после закрытия браузера. И обновим данные.
self.request.session.set_expiry(0)
self.request.session.modified = True
# В противном случае сеанс браузера будет таким же как время сеанса cookie "SESSION_COOKIE_AGE", определенное в settings.py
return super(CustomLoginView, self).form_valid(form)
-
Первое, что мы сделали, это установили
form_classатрибут на наш пользовательский,LoginFormтак как мы больше не используем значение по умолчаниюAuthenticationForm. -
Затем мы переопределяем
form_validметод, который вызывается при публикации действительных данных формы. Внутри этого метода мы проверяли, установлен ли флажокRemember_me. -
Если этот флажок не установлен, сеанс автоматически истечет при закрытии браузера. Но для пользователей, которые установят флажок
Remember_me, сеанс будет длиться до тех пор, пока мы определяем его вsettings.py.
Итак, давайте продолжим и установим SESSION_COOKIE_AGE 30 дней (или столько, сколько вы хотите) в настройках settings.py:
SESSION_COOKIE_AGE = 60 * 60 * 24 * 30
Теперь внутри нашего urls.py давайте сопоставим желаемый маршрут входа с соответствующим CustomLoginView. И сразу давайте также создадим маршрут выхода из системы, который будет обрабатываться встроенным LogoutView:
from django.urls import path
from .views import SignUpView, CustomLoginView
from django.contrib.auth import views as auth_views
urlpatterns = [
path("signup/", SignUpView.as_view(), name="signup"),
path('login/', CustomLoginView.as_view(redirect_authenticated_user=True, template_name='registration/login.html'), name='login'),
path('logout/', auth_views.LogoutView.as_view(template_name='registration/logout.html'), name='logout'),
]
-
redirect_authenticated_user=Trueозначает, что пользователи, пытающиеся получить доступ к странице входа после аутентификации, будут перенаправлены обратно.
Нам осталось только добавить шаблон выхода, а именно registration/logout.html.
У нас в settings.py добавлена строка:
LOGOUT_REDIRECT_URL = "/"
Она сделана для того, чтобы не использовать страницу после выхода пользователя, а делать редирект на главную страницу.
Давайте удалим ту строку, и добавим файл registration/logout.html следующего содержания:
{% extends "blog/base.html" %}
{% block title %}Logout{% endblock title %}
{% block content %}
<div>
<h5>You have been logged out</h5>
<hr>
<a href="{% url 'login' %}">Log In again</a>
</div>
{% endblock content %}
Давайте проверим что мы сделали, запустим сервер и перейдем на страницу http://127.0.0.1:8000/accounts/login/:
Мы видим что на странице авторизации у нас появился checkbox Remember me:. И теперь после авторизации мы принимаем файл Cookie, проверим это:
Теперь попробуем выйти из системы:
И теперь мы видим сообщение о выходе.
И последнее в этом шаге, но не менее важное - лучше перенаправить пользователя на страницу входа после регистрации. Давайте добавим новый метод в нашу функцию SignUpView чтобы она приняла следующий вид:
class SignUpView(generic.CreateView):
form_class = SignUpForm
success_url = reverse_lazy("login")
initial = None # принимает {'key': 'value'}
template_name = 'registration/signup.html'
def dispatch(self, request, *args, **kwargs):
# перенаправит на домашнюю страницу, если пользователь попытается получить доступ к странице регистрации после авторизации
if request.user.is_authenticated:
return redirect(to='/')
return super(SignUpView, self).dispatch(request, *args, **kwargs)
def get(self, request, *args, **kwargs):
form = self.form_class(initial=self.initial)
return render(request, self.template_name, {'form': form})
def post(self, request, *args, **kwargs):
form = self.form_class(request.POST)
if form.is_valid():
form.save()
username = form.cleaned_data.get('username')
messages.success(request, f'Account created for {username}')
return redirect(to='login') # редирект на страницу логина после регистрации
return render(request, self.template_name, {'form': form})
Мы добавили новую функцию dispatch, она проверит авторизован ли пользователь, если пользователь авторизован, то он не сможет попасть на страницу регистрации.
И ниже в методе post изменили redirect(to='login') при валидной форме отправки запроса. Чтобы после регистрации пользователь был отправлен на страницу авторизации.