Django – #15 – System Autoryzacji cz. 3

Wprowadzenie.

W trzeciej części poświęconej systemowi autoryzacji przedstawię w jaki sposób wykonać oraz obsłużyć rejestrowanie użytkowników.

Zakres artykułu.

  • System rejestracji użytkowników
  • Testy

System rejestracji użytkowników

W pierwszym kroku stwórzmy konto superusera w celu łatwiejszego monitorowania bazy danych, do której będziemy zapisywać dane naszych użytkowników. W tym celu w konsoli wpiszmy polecenie python3 manage.py createsuperuser i wprowadźmy dane o które nas pytają.

W kolejnym kroku zmodyfikujemy plik views.py. Zaimportujmy do naszego pliku następujące komponenty.

from django.shortcuts import redirect
from django.contrib.auth.models import User
from django.contrib.auth import authenticate
from django.contrib import auth

Funkcja redirect (link do dokumentacji) jest odpowiedzialna za przekierowania na inne strony.
Klasa User (link do dokumentacji) jest odpowiedziala za wiele czynności związanych z użytkownikami.
Metoda authenticate (link do dokumentacji) jest odpowiedzialna za weryfikowanie użytkownika.
auth (link do dokumentacji) jest to framework słóżący do autoryzacji.
contrib (link do dokumentacji) jest to paczka zawierająca różne frameworki.

Następnie wprowadźmy zmiany w funkcji def home(request):, tak abyśmy wiedzieli, czy udało nam się pomyśle zalogować czy też nie. Do tego celu wykorzystamy atrybut is_authenticated (link do dokumentacji), który słoży jedynie do odczytu i zwraca wartość True, dla każdego zalogowanego użytkownika. Kod zmodyfikowanej funkcji wygląda następująco.

def home(request):
    context = {}
    if request.user.is_authenticated:
        # Do something for authenticated users.
        context['userStatus'] = 'zalogowany'
    else:
        # Do something for anonymous users.
        context['userStatus'] = 'niezalogowany'
    return render(request, 'auth_system/home.html', context)

Kolejno przeprowadźmy modyfikację szablonu home.html, gdzie tak naprawdę dodamy zmienną odpowiedzialną za informowanie czy jesteśmy zalogowani czy też nie.

{% extends 'auth_system/base.html' %}

{% block content %}
  <div class="container">
    <h2>HOME</h2>
    {{ userStatus }}
  </div>
{% endblock %}

Gdy wczytamy stronę domowa powinniśmy otrzymać następujący efekt.

W kolejnym kroku zajmiemy się modyfikacją szablonu signup.html. W tym celu stworzymy formularz, który będzie zawierał takie pola jak nazwa użytkownika, hasło oraz powtórzenie hasła. Pola jakie jeszcze mamy dostępne w django dla konta użytkownika znajdują się w dokumentacji. Na stronie warto też przeznaczyć miejsce na wyświetlanie ewentualnych błędów podczas rejestracji, jak na przykład informację o tym, że podana nazwa użytkownika została już zajęta lub podane hasła nie pasują do siebie. W tym celu możemy zastosować konstrukcję {% if error %} {{ error }} {% endif %}. Warto zaznaczyć, że nazwa error to jedynie nasza własna nazwa zmiennej, która zostanie dodana w widoku signup_page. Zmodyfikowany kod szablonu wygląda następująco.

{% extends 'auth_system/base.html' %}

{% block content %}
  <div class="container">
    <h2>SIGNUP</h2><br>

    {% if error %}
      <div class="alert alert-danger">
        {{ error }}<br>
      </div>
    {% endif %}

    <form method="POST">
      {% csrf_token %}
      Nazwa użytkownika:<br>
      <input type="text" name="username"><br><br>
      Hasło:<br>
      <input type="password" name="password1"><br><br>
      Potwierdź hasło:<br>
      <input type="password" name="password2"><br><br>

      <input class="btn btn-primary" type="submit" value="Zarejestruj">
    </form>
  </div>
{% endblock %}

Natomiast wizualizacja kodu na stronie prezetuje się tak.

Przejdźmy teraz do widoku, który będzie obsługiwał nasz fomularz, czyli do funkcji def singup_page(request):. W pierwszej kolejności musimy rozróżnić przypadki, kiedy strona jest wywoływana przez metodę POST oraz metodę GET. Aby zrealizować to zadanie należy skorzystać z wyrażenia if request.method == ‚POST’: lub if request.method == ‚GET’:. W przypadku jeżeli zapytanie będzie wykonane przy pomocy metody GET, wówczas należy zwrócić pusty formularz, natomiast w przypadku metody POST to już my będziemy wysyłać dane z formularza i należy teraz rozpatrzeć kilka przypadków. W pierwszej kolejności musimy sprawdzić, czy podana nazwa użytkownika nie znajduje się już w bazie danych. Przypadek ten zrealizujemy poprzez wyrażenie User.objects.get(username=request.POST[‚username’]) które zwraca obiekt klasy User o nazwie użytkownika username wysłanego metodą POST. W przypadku kiedy podana nazwa użytkownika nie będzie istniała w bazie danych zostanie zwrócony wyjątek User.DoesNotExist. Oznacza to że podana nazwa użytkownika nie istnieje i możemy przejść do rozpatrywania kolejnego przypadku. Jeżeli natomiast podana nazwa użytkownika jest już użyta, warto poinformować o tym osobę która się rejestruje i podpowiedzieć jej, by wpisała inną nazwę użytkownika. W tym celu dodajmy do naszego słownika zmienną error (zmienna ta już została użyta w szablonie) i przypiszmy jej stosowny komunikat. Następnie możemy wrócić do strony rejestracji.

W przypadku jeżeli podana nazwa użytkownika nie istnieje, wówczas warto sprawdzić, czy podane hasła pasują do siebie. Wyrażenie, które zastosowałem sprawdza czy hasła są różne i wygląda następująco if request.POST[‚password1’] != request.POST[‚password2’]:. Jeżeli hasła są różne to dodajemy zmienną error i podobnie jak wcześniej jako wartość tego klucza podajemy stosowany komunikat, a następnie przechodzimy do strony rejestracji. W przeciwnym wypadku możemy przejść do procedury stworzenia nowego użytkownika. Tworzenie użytkownika realizowane jest poprzez wyrażenie user = User.object.create_user(request.POST[‚username’], password=request.POST[‚password1’]). Następnie możemy dokonać automatycznego zalogowania użytkownika przy pomocy wyrażenia auth.login(request, user). Następnie przy pomocy przekierowania przejdźmy do strony domowe.

Omówiony wyżej kod prezentuje się następująco.

def signup_page(request):
    context = {}
    if request.method == 'POST':
        # Request for sign up
        # Check if user is available
        try:
            user = User.objects.get(username=request.POST['username'])
            context['error'] = 'Podana nazwa użytkownika już istnieje! Proszę podać inną nazwę użytkownika.'
            return render(request, 'auth_system/signup.html', context)
        except User.DoesNotExist:
            # Check if the password1 is equal to the password2
            if request.POST['password1'] != request.POST['password2']:
                context['error'] = 'Podane hasła nie są takie same! Proszę wprowadzić identyczne hasła.'
                return render(request, 'auth_system/signup.html', context)
            else:
                # Create new user
                user = User.objects.create_user(request.POST['username'], password=request.POST['password1'])
                # Automatic login after signing up
                auth.login(request, user)
                # Go to home page
                return redirect('home')
    else:
        return render(request, 'auth_system/signup.html', context)

Natomiast cały plik na chwilę obecną wygląda w taki sposób.

from django.shortcuts import render, redirect
from django.contrib.auth.models import User
from django.contrib.auth import authenticate
from django.contrib import auth


# Create your views here.


def home(request):
    context = {}
    if request.user.is_authenticated:
        # Do something for authenticated users.
        context['userStatus'] = 'zalogowany'
    else:
        # Do something for anonymous users.
        context['userStatus'] = 'niezalogowany'
    return render(request, 'auth_system/home.html', context)

def signup_page(request):
    context = {}
    if request.method == 'POST':
        # Request for sign up
        # Check if user is available
        try:
            user = User.objects.get(username=request.POST['username'])
            context['error'] = 'Podana nazwa użytkownika już istnieje! Proszę podać inną nazwę użytkownika.'
            return render(request, 'auth_system/signup.html', context)
        except User.DoesNotExist:
            # Check if the password1 is equal to the password2
            if request.POST['password1'] != request.POST['password2']:
                context['error'] = 'Podane hasła nie są takie same! Proszę wprowadzić identyczne hasła.'
                return render(request, 'auth_system/signup.html', context)
            else:
                # Create new user
                user = User.objects.create_user(request.POST['username'], password=request.POST['password1'])
                # Automatic login after signing up
                auth.login(request, user)
                # Go to home page
                return redirect('home')
    else:
        return render(request, 'auth_system/signup.html', context)

def login_page(request):
    return render(request, 'auth_system/login.html')

def logout_page(request):
    return render(request, 'auth_system/logout.html')

Testy

Gdy wejdziemy na stronę domową powinniśmy zobaczyć następujący rezultat.

Naciskając na przycisk Zarejestruj się powinniśmy przejść na stronę z naszym formularzem rejestracyjnym. Po wpisaniu nazwy użytkownika, która nie istnieje w bazie danych oraz haseł które pasują do siebie powinniśmy zostać przekierowani na stronę domową.

Na stronie domowej powinniśmy zobaczyć napis, że jesteśmy zalogowani.

Przechodząc do sekcji admina dodatkowo zobaczymy, że aktualnie jesteśmy zalogowani jako Jan oraz że nie mamy dostępu do tej części aplikacji. Dlatego następnie w panelu admina zalogujmy się jako superuser.

W kolejnym kroku przejdźmy do zakładki Users w celu sprawdzenia, czy rzeczywiście dokonaliśmy pomyślnej rejestracji.

Na koniec sprawdźmy, czy w przypadku ponownej rejestracji z tą samą nazwą użytkownika zobaczymy komunikat błędu.

Oraz przetestujmy drugi przypadek, gdzie podamy nową nazwę użytkownika, lecz hasła będą różne.

Jak widzimy testy przebiegły pomyśle co oznacza, że możemy teraz przejść do etapu logowania i wylogowywania.

Autor artykułu
Dominik Bednarski

One Reply to “Django – #15 – System Autoryzacji cz. 3”

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *