Сделать систему авторизации и регистрации пользователей на Django

Часы
16.10.2023
Часы
18.12.2024
Часы
6 минут
Глазик
233
Сердечки
0
Соединённые точки
0
Соединённые точки
0
Соединённые точки
0

Задача

Реализовать систему аутентификации пользователей. Для этого создаётся форма регистрации и форма для входа и выхода на сайте timthewebmaster.com.
Форма регистрации должна содержать следующие элементы:
  • имя пользователя ( требовать обязательно )
  • почту пользователя ( требовать обязательно )
  • пароль пользователя ( требовать обязательно )
  • повтор пароля пользователя ( требовать обязательно )
  • поле об самом пользователе
  • запрос аватарки пользователя
  • кнопки регистрации соответственно
Форма входа должна состоять только из двух полей:
  • имя пользователя
  • пароля пользователя
Ещё должна быть кнопка, которая бы позволяла выйти из режима аутентифицированного пользователя.

Решение

Подключение jQuery

Для решения данного кейса мне потребуется подключить одну библиотеку JS, jQuery. Это популярная , простая библиотека. И изменить настройки безопасности сайта написаного на django. То есть подправить файл settings.py

Предварительная настройка django для регистрации пользователей

На самом деле это необязательный шаг, ибо это не помешает общению сервера с клиентом. Но ради безопасности и уверенности, что никакие хакеры не взломают базу данных сервера и не получат конфиденциальные данные пользователей мы это настроим.
В файле settings.py добавь

CSRF_USE_SESSIONS = True
			
В приложении которое выполняет регистрацию открой urls.py и добавь 2 путя

from django.urls import path
from .views import signup, signup_verify


urlpatterns = [
	…
# Это путь на страницу которая будет видна пользователю
    path('signup/', signup, name='signup'), 
# Это путь/адрес который мы будем использовать чтобы общаться с сервером
    path('signup/verify-signup/', signup_verify, name='signup_verify'),
]
			

Пишем ajax запрос для формы регистрации

Теперь пишется JS-скрипт с запросом.

function OnSignup(){
	// Данные которые мы запросили у пользователя и которые мы отправим на сервер
	var form_data = new FormData();
	// Токен защиты ( про который говорилось выше)
	form_data.append("csrfmiddlewaretoken", csrftoken);
	// Имя пользователя
	form_data.append("username", $("#username").val())
	// Почта пользователя
	form_data.append("email", $("#email").val())
	// Пароль пользователя
	form_data.append("password",  $("#password").val())
	// Повтор пароля пользователя ( нужно будет сопоставить с первым)
	form_data.append("repeated_password", $("#repeated_password").val())
	// О пользователе
	form_data.append("about", $("#about").val())
	// Аватарка пользователя
	form_data.append("file", document.getElementById('file').files[0]);
	$.ajax({
		// Тип запроса. POST потому что мы не хотим чтобы данные были видны
		type: "POST",
		// Путь который мы задали для общения с сервером
		url: "verify-signup/",
		// Отправляемые данные
		data: form_data,
		processData: false,
		contentType: false,
		// Отправляем токен защиты
		headers: {'X-CSRFToken': csrftoken},
		mode: 'same-origin', 
		// Функция которая будет выполнена при успехе, код 200
		success: function(result) {
			$(".hint-required").css("color","green")
			$("#common-error").text(result.common)	
			$("#username-error").text(result.username)	
			$("#email-error").text(result.email)	
			$("#password-error").text(result.password)	
			$("#repassword-error").text(result.password)	
			// Redirect to login page
			setTimeout(function(){
				window.location.href =  '/login/'
			},3000)
		},
		// Функция которая будет выполнена при неудаче
		error: function(jqXHR, textStatus, errorThrown){
			$(".hint-required").css("color","red")
			$("#common-error").text(jqXHR.responseJSON.common)	
			$("#username-error").text(jqXHR.responseJSON.username)	
			$("#email-error").text(jqXHR.responseJSON.email)	
			$("#password-error").text(jqXHR.responseJSON.password)	
			$("#repassword-error").text(jqXHR.responseJSON.password)	
		}
	});
}

// Документ готов и загружен
$(document).ready( function(){
	// Пользователь нажал на кнопку регистрации
	$("#signup").on('click',OnSignup)
})
		
При успехе, то есть если все проверки пройдены, по типу длины пароля или существующей почты, мы вставим текст для обратной связи с пользователем и перенаправим на страницу входа.
При неудаче, мы сообщим об этом пользователю тоже.

Пишем функцию обработки ajax формы регистрации

В главе предварительной настройки мы импортировали в utls.py функцию signup_verify давай определим её

from django.shortcuts import render
from django.http import JsonResponse, HttpResponseRedirect
from django.template.defaultfilters import slugify
import re
from MyBlog import settings
from .models import User

...

def signup_verify(request):
    message = {
        'common': '',
        'username': 'обязательно',
        'email': 'обязательно',
        'password': 'обязательно',
        'repassword': 'обязательно',
    }
    status = 200
# Будем обрабатывать только POST запросы
    if request.method == 'POST':
        # Общий паттерн почты для сравнения
        regex = r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,7}\b'
	# Собираем данные которые отправили
        username = request.POST['username']
        email = request.POST['email']
        password = request.POST['password']
        repeated_password = request.POST['repeated_password']
        about = request.POST['about']
        avatar = None
        try:
            avatar = request.FILES['file']
        except:
            avatar = None

        message['common']='✖ не могу зарегестрировать нового пользователя'
        # Имя, почта, пароль пусты
        if len(username) == 0:
            message['username']='⚠ поле пользователя не заполнено'
            status = 406
        if len(email) == 0:
            message['email']='⚠ поле почты не заполнено'
            status = 406
        if len(password) == 0:
            message['password']='⚠ поле пароля не заполнено’
            status = 406
        # Проверка если пользователь уже существует
	if User.objects.filter(name=username).exists() or User.objects.filter(slug=slugify(username)).exists():
            message['username']='⚠ пользователь с таким именем уже существует'
            status = 406
        # Проверка если пользователь уже существует
        if User.objects.filter(email=email).exists():
            message['email']='⚠ такая почта уже используется'
            status = 406
        # Проверка если имя достаточно длинное
        if len(username) < 3:
            message['username']='⚠ введённое имя слишком короткое'
            status = 406
        # Проверка если имя слишком длинное
        if len(username) > 25:
            message['username']='⚠ введённое имя слишком длинное'
            status = 406
        # Проверка если пароль достаточно длинный
        if len(password) < 6:
            message['password']='⚠ введённый пароль слишком короткий'
            status = 406
        # Совпадают ли пароли
        if password != repeated_password:
            message['password']='⚠ пароль не совпадает'
            message['repassword']='⚠ пароль не совпадает'
            status = 406
        # Правильный ли формат у почты
        if not re.fullmatch(regex, email):
            message['email']='⚠ неправильный формат адреса почты'
            status = 406
        if status == 200:
            message['common'] = '✔ вы успешно зарегестрировались, перенаправление'
            message['username'] = '✔ Хорошо'
            message['email'] = '✔ Хорошо'
            message['password'] = '✔ Хорошо'
            message['repassword'] = '✔ Хорошо'
# Сохраняем данные из отправленной формы
            user = User(name=username, about=about, avatar=avatar, email=email, password=password)
            user.save()

        return JsonResponse(message, status=status)
    else:
        status = 403
        return JsonResponse(message, status=status)

		
Вот таким образом я выявляю “ошибки” форм в django.

Собираем всё вместе в html шаблоне. Страница регистрации

Теперь, чтобы всё заработало, мне нужно создать шаблон, который бы загрузил соответствующий скрипт и стили, использовал токен. Вот код формы

    {% csrf_token %}
	
	<div class="form">
		<form enctype="multipart/form-data" class="form_form" id="toSignup" action="send_new_user" method="get">
			<div>
				<input class="form_el" placeholder="имя" type="text" name="username" id="username">
				<div class="hint-container">
					<p id="username-error" class="hint-required">обязательно</p>
					<p class="hint-error">от 3 до 25 букв</p>
				</div>
			</div>
			<div>
				<input class="form_el" placeholder="почта" type="email" name="email" id="email">
				<div class="hint-container">
					<p id="email-error" class="hint-required">обязательно</p>
					<p class="hint-error">корректный адрес почты</p>
				</div>
			</div>
			<div>
				<input class="form_el" placeholder="пароль" type="password" name="password" id="password">
				<div class="hint-container">
					<p id="password-error" class="hint-required">обязательно</p>
					<p class="hint-error">от 6 букв</p>
				</div>
			</div>
			<div>
				<input class="form_el" placeholder="повтори пароль" type="password" name="repeated_password"  id="repeated_password">
				<div class="hint-container">
					<p id="repassword-error" class="hint-required">обязательно</p>
					<p class="hint-error">должен совпадать с паролем</p>
				</div>
			</div>
			<textarea class="form_el__about" placeholder="Раскажи немного о себе" name="about" rows=4  id="about"></textarea>
		</form> 
	</div>
	<div class="sel_file">
		<label for="texta">Выбери себе аватар.</label>
		<input class="form_el__file" placeholder="выбрать файл" type="file" name="file" id="file">
	</div>
	<div class="buttons">
		<div id="signup" class="button button-middle">
			<a>Регистрация</a>
		</div>
	</div>

		
А в самом низу перед тегом body вставить написаный заранее скрипт



    <!-- Загрузка jQuery --> 
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    {% csrf_token %}
    <!-- Нужно сохранить csrf токен в JS переменную чтобы потом использовать в написанном ранее скрипте -->
    <script>
        const csrftoken = document.querySelector('[name=csrfmiddlewaretoken]').value;
    </script>
<!-- Загрузка ранее написанного скрипта запроса регистрации -->
    <script src="{% static 'User/js/signup.js' %}"></script>



		

Донастраиваем URLs для формы аутентификации пользователей

Нужно добавить 2 дополнительных путя и импортировать соответствующие функции

...
from .views import login, login_verify, logout


urlpatterns = [
	…
# Эта функция очистит сессию от созданных ранее переменных
    path('logout/', logout, name='logout'),
# Эта функция отобразит форму входа для пользователя
    path('login/', login, name='login'),
# Эта функция задаст соответствующие переменные сессии для соответствующего пользователя и решит можен ли он войти или нет
    path('login/verify-login/', login_verify, name='login_verify'),
]
		

Пишем ajax запрос для формы аутентификации пользователя

Принцип тот же что и при регистрации. Указываем тип запроса, url-запроса и данные которые хотим передать. Ну и дополнительно, конечно, обратная связь для пользователя. Чтобы он знал об ошибках которые он допустил при заполнении формы. Всё это в отдельном файле login.js

function OnLogin(){
	var username = $("#username").val()	
	var password = $("#password").val()	
	$.ajax({
		type: "POST",
		url:  'verify-login/',
		data: {
			'username': username,
			'password': password,
		},
		headers: {'X-CSRFToken': csrftoken},
		mode: 'same-origin', 
		success: function(result){
			$(".hint-required").css("color","green")
			$("#common-error").text(result.common)	
			$("#username-error").text(result.username)	
			$("#password-error").text(result.password)	
			setTimeout(function(){
				window.location.href = '/' + language_code + '/'
			},1000)
		},
		error: function(jqXHR, textStatus, errorThrown){
			$(".hint-required").css("color","red")
			$("#common-error").text(jqXHR.responseJSON.common)	
			$("#username-error").text(jqXHR.responseJSON.username)	
			$("#password-error").text(jqXHR.responseJSON.password)	
		}
	})
}
// Документ готов и загружен
$(document).ready( function(){
	// Пользователь нажал на кнопку входа
	$("#login").on('click',OnLogin)
})
		

Пишем функцию/форму обработки ajax запроса аутентификации пользователя

Вот готовые функции для обработки и проверки данных введённых пользователем

def login_verify(request):
    message = {
        'common': '',
        'username': 'обязательно',
        'password': 'обязательно',
    }
    status = 200
    if request.method == 'POST':
        username = request.POST['username']
        password = request.POST['password']
        message['common']='✖ не могу войти'
        if len(username) == 0:
            message['username']='⚠ пользователь пуст'
            status = 406
        if len(password) == 0:
            message['password']='⚠ пароль пуст'
            status = 406
        required_user = User.objects.filter(name=username)
	# Пользователь существует
        if required_user.exists():
          Введённый пароль совпадает с сохранённым  
	if required_user.first().password == password:
                status = 200
		# Задаём статус текущей сессии как зарегестрированной
                request.session["is_auth"] = True
		# Сохраняем имя пользователя в переменной текущей сессии
		# Это может пригодиться для отображения информации предназначеной
		# Только пользователю
                request.session["username"] = username
                message['common'] = '✔ Вы успешно вошли, перенаправление ... '
                message['username'] = '✔ Хорошо'
                message['password'] = '✔ Хорошо'
            else:
                message['password'] = '⚠ Неправильный пароль'
                status = 406
        else:
            message['username'] = '⚠ Такого пользователя не существует'
            status = 406

        return JsonResponse(message, status=status)

		
Функция выхода пользователя. Я просто очищаю текущую сессию пользователя на моём сайте. И перенаправляю на страницу входа на сайт.

def logout(request):
    request.session.flush()
    return HttpResponseRedirect("/login")
		

Пишем шаблон аутентификации на сайт

Ну и конечно мой шаблон для входа на сайт



	<div id="common-error" class="hint-container hint-required hint-common_error"></div>
    {% csrf_token %}
	<div class="form">
		<form  class="form_form form_login" id="toLogin" action="send_new_user" method="get">
			<div>
				<input class="form_el" placeholder="имя" type="text" name="username" autocomplete="off" id="username"><br><br>
				<div class="hint-container">
					<p id="username-error" class="hint-required">обязательно</p>
				</div>
			</div>
			<div>
				<input class="form_el" placeholder="пароль" type="password" name="password" autocomplete="off" id="password"><br><br>
				<div class="hint-container">
					<p id="password-error" class="hint-required">обязательно</p>
				</div>
			</div>
		</form> 
	</div>
	<div class="buttons">
		<div id="login" class="button button-middle">
			<a>Вход</a>
		</div>
		<div class="button button-middle">
			<a href="{% url 'signup' %}">
			Регистрация
			</a>
		</div>
	</div>


		
И конечно же незабываем вставить скрипт в шаблон. Написаный нами login.js и jQuery библиотеку



 	<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    {% csrf_token %}
    <script>
        const csrftoken = document.querySelector('[name=csrfmiddlewaretoken]').value;
    </script>
    <script src="{% static 'User/js/login.js' %}"></script>


		

Вывод

В данном кейсе я продемонстрировал две основные формы для системы аутентификации пользователей. Форму регистрации и форму входа. Не самое сложное дело, особенно если знаешь что делаешь.
Сразу хочу оговориться, я не добавлял сюда капчу или проверку почты по одной простой причине. Это аутентификация на моём сайте и мне этого не требовалось. В моей деятельности важно не количество пользователей, а их качество. То есть, если человек захочет связаться со мной он свяжется, если нет ну это его дело.

Дополнительные материалы

Github репозиторий

Репозиторий, который я использую чтобы разрабатывать данный сайт
Конкретно в данном кейсе вас будут интересовать следующие файлы:

Материалы которыми пользовался


Комментарии

(0)

captcha
Отправить
Сейчас тут пусто. Буть первым (o゚v゚)ノ

Другое

Использованные термины


Релевантные вопросы


Похожие статьи


Комментарии на сайт используя Django

Часы
11.11.2023
В этой статье я покажу, как я реализовывал комментирование на моём сайте. Комментирование, которое доступно как анонимам, так и зарегестрированным пользователям.

Как реализовать регистрацию и логирование пользователей

Часы
30.10.2023
Сразу оговорюсь, что система аутентификации, которую мы с тобой будем писать не основана на встроеном приложении django, django.contrib.auth . Это будет отдельное приложение с отдельной моделью к ней.