image
22 marca 2023

Zarządzanie użytkownikami i uwierzytelnianie w Django

22 marca 2023

W erze cyfrowej, bezpieczeństwo jest podstawowym zagadnieniem dla każdej aplikacji internetowej. Kluczowym elementem tego bezpieczeństwa jest zapewnienie, że użytkownicy są tymi, za kogo się podają, oraz że mogą uzyskać dostęp jedynie do tych części aplikacji, do których mają uprawnienia. To jest miejsce, gdzie pojawiają się uwierzytelnianie i autoryzacja użytkowników.

 

Uwierzytelnianie to proces weryfikacji tożsamości użytkownika, zazwyczaj za pomocą kombinacji nazwy użytkownika i hasła. Autoryzacja, z kolei, określa, co użytkownik ma prawo robić i do jakich zasobów może uzyskać dostęp po uwierzytelnieniu.

 

Django oferuje solidny system zarządzania zarówno uwierzytelnianiem, jak i autoryzacją. Jego wbudowane możliwości pozwalają twórcom na tworzenie bezpiecznych aplikacji bez konieczności wynajdywania koła na nowo.

 

W tym wpisie na blogu zagłębimy się w system uwierzytelniania i autoryzacji Django, eksplorując, jak rejestrować użytkowników, uwierzytelniać ich, zarządzać hasłami, autoryzować użytkowników, a nawet dostosowywać te procesy do unikalnych potrzeb Twojej aplikacji.

 

 

Zrozumienie uwierzytelniania i autoryzacji

 

Zanim zagłębimy się w aspekty techniczne, ważne jest, aby jasno rozróżnić dwa kluczowe terminy: uwierzytelnianie i autoryzację. Te dwa pojęcia są fundamentalne dla zrozumienia bezpieczeństwa aplikacji internetowych.

 

Uwierzytelnianie(Authentication) to proces weryfikacji tożsamości użytkownika. Kiedy użytkownicy podają swoją nazwę użytkownika (lub e-mail) i hasło, system porównuje te informacje z danymi przechowanymi. Jeśli dane się zgadzają, system potwierdza, że użytkownicy są rzeczywiście tymi, za kogo się podają. Innymi słowy, uwierzytelnianie odpowiada na pytanie: "Kim jest użytkownik?"

 

 Autoryzacja(Authorization) natomiast następuje po uwierzytelnieniu i określa uprawnienia, jakie użytkownik posiada w systemie. Po uwierzytelnieniu użytkowników, system wie, kim są. Następnym krokiem jest określenie, co mogą robić. Autoryzacja odpowiada na pytanie: "Co użytkownik ma prawo robić?" Dotyczy to uprawnień i ról kontrolujących dostęp do zasobów i operacji.

 

Należy podkreślić, że uwierzytelnianie zawsze poprzedza autoryzację. System musi najpierw wiedzieć, kim jest użytkownik, zanim przypisze mu odpowiednie uprawnienia.

 

W kontekście Django, dostarcza ono wbudowany system zarówno do uwierzytelniania, jak i autoryzacji, który szczegółowo omówimy w kolejnych sekcjach.

 

 

System uwierzytelniania Django

 

Framework Django posiada solidny wbudowany system uwierzytelniania, który zajmuje się zarządzaniem użytkownikami, zarządzaniem sesjami, a nawet zawiera narzędzia do powszechnych zadań, takich jak resetowanie haseł i obsługa formularzy do logowania i wylogowywania.

 

System uwierzytelniania w Django opiera się na modelu User, który jest wbudowanym modelem (tabelą bazy danych) do przechowywania informacji o użytkownikach. Zawiera pola takie jakusername, password, email, first_name, last_name, i kilka innych. Hasła są przechowywane jako zahashowane wartości dla zwiększenia bezpieczeństwa.

 

System uwierzytelniania Django oferuje następujące możliwości:

 

Rejestracja użytkowników: Użytkownicy mogą tworzyć konto w Twojej aplikacji.

 

Logowanie użytkowników: Użytkownicy mogą zalogować się na swoje konto za pomocą swoich danych uwierzytelniających.

 

Wylogowanie użytkowników: Użytkownicy mogą bezpiecznie wylogować się ze swojego konta.

 

Zarządzanie hasłami: Django automatycznie zajmuje się hashowaniem haseł i ich porównywaniem. Zapewnia także narzędzia do obsługi resetowania haseł.

 

Zarządzanie sesjami: Django zarządza sesjami użytkowników, umożliwiając śledzenie danych użytkownika między żądaniami.

 

Zarządzanie grupami i uprawnieniami: Django pozwala na definiowanie grup uprawnień i przypisywanie ich użytkownikom.

 

System uwierzytelniania jest domyślnie dołączany podczas tworzenia nowego projektu Django. Możesz go znaleźć w INSTALLED_APPS w pliku ustawień jako 'django.contrib.auth'.

 

W kolejnych sekcjach szczegółowo omówimy, jak wykorzystać te funkcje w twojej aplikacji Django.

 

Rejestracja użytkowników w Django

 

Rejestracja użytkowników to proces, w którym nowy użytkownik podaje niezbędne informacje, takie jak nazwa użytkownika i hasło, aby utworzyć nowe konto w aplikacji. Django dostarcza narzędzi, które ułatwiają ten proces.

 

Stwórzmy prosty formularz rejestracyjny przy użyciu wbudowanego w Django UserCreationForm. Ten formularz zawiera pola dla nazwy użytkownika i hasła.

 

# in your views.py
from django.contrib.auth.forms import UserCreationForm
from django.shortcuts import render, redirect

def register(request):
    if request.method == 'POST':
        form = UserCreationForm(request.POST)
        if form.is_valid():
            form.save()
            return redirect('login')  # redirect to login page after successful registration
    else:
        form = UserCreationForm()
    return render(request, 'register.html', {'form': form})

 

W powyższym kodzie, nowa instancja formularza jest tworzona, gdy metoda żądania to GET. Gdy metoda żądania to POST (kiedy formularz jest wysyłany), formularz jest inicjowany z request.POST (wysłane dane formularza). Następnie formularz jest sprawdzany za pomocą form.is_valid(). Jeśli formularz jest prawidłowy, jest zapisywany, co tworzy nowego użytkownika, a następnie użytkownik jest przekierowywany na stronę logowania.

 

Oto, jak zaimplementować odpowiadający mu formularz HTML w szablonie register.html, używając klas Bootstrap do stylizacji:

 

{% extends 'base_generic.html' %}

{% block content %}
  <h2>Register</h2>
  <form method="post" class="form-group">
  {% csrf_token %}
    {% for field in form %}
      <label for="{{ field.id_for_label }}" class="form-label">{{ field.label }}</label>
      {{ field|add_class:"form-control" }}
      {% if field.help_text %}
        <small class="form-text text-muted">{{ field.help_text }}</small>
      {% endif %}
      {% for error in field.errors %}
        <div class="alert alert-danger" role="alert">
          {{ error }}
        </div>
      {% endfor %}
    {% endfor %}
    <button type="submit" class="btn btn-primary mt-3">Register</button>
  </form>
{% endblock %}

 

 

W tym szablonie używamy klas Bootstrap: form-group, form-label, form-control, form-text, alert i btn do stylizacji formularza i jego komponentów. Filtr szablonu add_class jest używany do dodania klasy form-control do pól formularza.

 

Po utworzeniu widoku i szablonu, nie zapomnij przypisać widoku do URL-a w pliku urls.py.

 

# in your urls.py
from django.urls import path
from .views import register

urlpatterns = [
    path('register/', register, name='register'),
]

 

 

Ten podstawowy proces rejestracji można dalej dostosować do własnych potrzeb, co omówimy w zaawans

 

 

Autentykacja użytkowników w Django

 

Po zarejestrowaniu użytkownicy potrzebują sposobu, aby zalogować się do aplikacji. Django dostarcza metodę autentykacji, która sprawdza dane uwierzytelniające użytkownika i loguje go do systemu.

 

Stwórzmy prosty widok logowania, używając wbudowanego w Django formularza AuthenticationForm. Formularz ten zawiera pola dla nazwy użytkownika i hasła.

 

# in your views.py
from django.contrib.auth import authenticate, login
from django.contrib.auth.forms import AuthenticationForm
from django.shortcuts import render, redirect

def login_view(request):
    if request.method == 'POST':
        form = AuthenticationForm(request, data=request.POST)
        if form.is_valid():
            username = form.cleaned_data.get('username')
            password = form.cleaned_data.get('password')
            user = authenticate(username=username, password=password)
            if user is not None:
                login(request, user)
                return redirect('home')  # redirect to home page after successful login
    else:
        form = AuthenticationForm()

    return render(request, 'login.html', {'form': form})

 

 

W funkcji login_view tworzymy instancję AuthenticationForm, gdy metoda żądania to POST, a następnie walidujemy formularz za pomocą form.is_valid(). Jeżeli formularz jest prawidłowy, autentykujemy użytkownika za pomocą funkcji authenticate(), która sprawdza dane uwierzytelniające użytkownika. Jeżeli użytkownik istnieje i hasło jest poprawne, funkcja authenticate() zwraca obiekt User. Następnie logujemy użytkownika za pomocą funkcji login().

 

Odpowiadający formularz HTML w szablonie login.html może wyglądać tak:

 

{% extends 'base_generic.html' %}

{% block content %}
  <h2>Login</h2>
  <form method="post" class="form-group">
  {% csrf_token %}
    {% for field in form %}
      <label for="{{ field.id_for_label }}" class="form-label">{{ field.label }}</label>
      {{ field|add_class:"form-control" }}
      {% if field.help_text %}
        <small class="form-text text-muted">{{ field.help_text }}</small>
      {% endif %}
      {% for error in field.errors %}
        <div class="alert alert-danger" role="alert">
          {{ error }}
        </div>
      {% endfor %}
    {% endfor %}
    <button type="submit" class="btn btn-primary mt-3">Login</button>
  </form>
{% endblock %}

 

Po utworzeniu widoku i szablonu, przypisz widok do URL-a w pliku urls.py.

 

# in your urls.py
from django.urls import path
from .views import login_view

urlpatterns = [
    path('login/', login_view, name='login'),
]

 

Aby wylogować użytkownika, Django dostarcza funkcję logout. Oto prosty widok wylogowania:

 

# in your views.py
from django.contrib.auth import logout
from django.shortcuts import redirect

def logout_view(request):
    logout(request)
    return redirect('home')  # or 'login'

 

I odpowiadające mapowanie URL:

 

# in your urls.py
from django.urls import path
from .views import logout_view

urlpatterns = [
    path('logout/', logout_view, name='logout'),
]

 

Poprzez wywołanie funkcji logout(request), Django wyloguje użytkownika powiązanego z bieżącą sesją.

 

 

Zarządzanie hasłami użytkowników w Django

 

Zarządzanie hasłami użytkowników w sposób bezpieczny jest kluczowym elementem uwierzytelniania użytkowników. Django dostarcza wbudowane narzędzia do haszowania, zmiany i resetowania haseł, co może znacznie uprościć ten proces.

 

Kiedy użytkownik jest tworzony za pomocą formularza UserCreationForm w Django, hasło jest automatycznie haszowane za pomocą algorytmu haszującego haseł określonego w ustawieniach projektu. Domyślnie Django używa algorytmu PBKDF2 z hashem SHA256, który jest obecnie uważany za bezpieczny. Haszowane hasło jest następnie przechowywane w bazie danych, a oryginalne hasło w postaci czystego tekstu jest porzucane.

 

Kiedy użytkownik próbuje się zalogować, dostarczone przez niego hasło jest haszowane za pomocą tego samego algorytmu, a wynikowy hash jest porównywany z przechowywanym hashem. Jeśli hashe pasują, hasło jest poprawne i użytkownik jest uwierzytelniony.

 

Zmiana haseł

 

Django dostarcza wbudowany formularz, PasswordChangeForm, który może być używany do zmiany hasła użytkownika. Ten formularz wymaga od użytkownika wprowadzenia starego hasła i dwukrotnego wprowadzenia nowego hasła.

 

Oto, jak możesz stworzyć widok do obsługi zmiany hasła:

 

# in your views.py
from django.contrib.auth import update_session_auth_hash
from django.contrib.auth.forms import PasswordChangeForm
from django.shortcuts import render, redirect

def change_password(request):
    if request.method == 'POST':
        form = PasswordChangeForm(request.user, request.POST)
        if form.is_valid():
            user = form.save()
            update_session_auth_hash(request, user)  # Important!
            return redirect('change_password_done')
    else:
        form = PasswordChangeForm(request.user)

    return render(request, 'change_password.html', {'form': form})

 

Funkcja update_session_auth_hash() jest używana do utrzymania użytkownika zalogowanym po zmianie hasła.

 

Szablon change_password.html może wyglądać tak:

 

{% extends 'base_generic.html' %}

{% block content %}
  <h2>Change Password</h2>
  <form method="post" class="form-group">
  {% csrf_token %}
    {% for field in form %}
      <label for="{{ field.id_for_label }}" class="form-label">{{ field.label }}</label>
      {{ field|add_class:"form-control" }}
      {% if field.help_text %}
        <small class="form-text text-muted">{{ field.help_text }}</small>
      {% endif %}
      {% for error in field.errors %}
        <div class="alert alert-danger" role="alert">
          {{ error }}
        </div>
      {% endfor %}
    {% endfor %}
    <button type="submit" class="btn btn-primary mt-3">Change Password</button>
  </form>
{% endblock %}

 

Resetowanie haseł

 

Django dostarcza również zestaw widoków do resetowania haseł. Te widoki obsługują proces wysyłania e-maila z resetowaniem hasła, generowania jednorazowego tokenu i resetowania hasła.

 

Aby umożliwić funkcję resetowania hasła, musisz dołączyć do konfiguracji URL swojego projektu auth.urls z Django:

 

# in your urls.py
from django.urls import path, include

urlpatterns = [
    path('accounts/', include('django.contrib.auth.urls')),  # add this
]

 

To uwzględni kilka widoków, w tym password_reset, password_reset_done, password_reset_confirm i password_reset_complete. Musisz stworzyć szablony dla każdego z tych widoków (password_reset_form.html, password_reset_done.html, password_reset_confirm.html i password_reset_complete.html).

 

Django pozwala na znaczne dostosowanie tych formularzy i widoków do indywidualnych potrzeb twojej aplikacji. Na przykład, możesz chcieć dostosować e-mail resetowania hasła, użyć własnych szablonów lub dostarczyć dodatkowe informacje do formularzy.

 

 

Autoryzacja użytkowników w Django

 

Po zalogowaniu użytkowników musisz określić, co mogą zrobić. Ten proces nazywa się autoryzacją. Django oferuje elastyczny i potężny system uprawnień i autoryzacji "od ręki".

 

Uprawnienia (Permissions)

 

W Django uprawnienie to konkretne działanie, które użytkownik może mieć pozwolenie na wykonanie. Django automatycznie tworzy uprawnienia dla każdego modelu, dla operacji dodawania, zmiany i usuwania. Możesz również zdefiniować własne niestandardowe uprawnienia na poziomie modelu.

 

Możesz sprawdzić, czy użytkownik ma konkretne uprawnienie, używając metody user.has_perm('app_label.permission'). Na przykład, aby sprawdzić, czy użytkownik ma uprawnienia do dodania książki, możesz zrobić:

 

if request.user.has_perm('library.add_book'):
    # The user can add a book
else:
    # The user cannot add a book

 

Grupy użytkowników(User Groups)

 

Dla łatwiejszego zarządzania uprawnieniami możesz tworzyć grupy użytkowników. Możesz przypisać uprawnienia do grupy, a wszyscy użytkownicy w tej grupie będą mieć te uprawnienia. Grupy można tworzyć i zarządzać poprzez stronę administracyjną Django.

 

Sprawdzanie, czy użytkownik jest uwierzytelniony

 

W swoich widokach możesz sprawdzić, czy użytkownik jest uwierzytelniony, używając właściwości user.is_authenticated. Może to być użyte do ograniczania dostępu do widoków dla zalogowanych użytkowników. Na przykład:

 

def my_view(request):
    if request.user.is_authenticated:
        # The user is logged in
    else:
        # The user is not logged in

 

Dekorator login_required

 

Jeśli chcesz ograniczyć widok tylko do zalogowanych użytkowników, możesz użyć dekoratora login_required:

 

from django.contrib.auth.decorators import login_required

@login_required
def my_view(request):
    # This view is only accessible to logged-in users

 

Jeśli nieuwierzytelniony użytkownik próbuje uzyskać dostęp do tego widoku, zostanie przekierowany do strony logowania.

 

UserPassesTestMixin

 

Jeśli potrzebujesz bardziej złożonych sprawdzeń autoryzacji, możesz użyć klasowych widoków Django i UserPassesTestMixin. Ten mixin pozwala zdefiniować funkcję testową, którą użytkownik musi zdać, aby uzyskać dostęp do widoku. Na przykład:

 

from django.contrib.auth.mixins import UserPassesTestMixin
from django.views.generic import TemplateView

class MyView(UserPassesTestMixin, TemplateView):
    template_name = 'my_template.html'

    def test_func(self):
        return self.request.user.username == 'admin'

 

W tym przykładzie tylko użytkownik o nazwie 'admin' może uzyskać dostęp do widoku.

 

Pamiętaj, że system uprawnień i autautoryzacji Django został zaprojektowany tak, aby dać Ci tyle kontroli, ile potrzebujesz, jednocześnie upraszczając typowe przypadki.

 

 

Zaawansowane tematy: Model użytkownika Django

 

Model User jest jednym z wbudowanych modeli Django, zaprojektowanym do obsługi typowych zadań związanych z użytkownikami. Zawiera pola takie jak username, password, email, first_name, last_name i inne. Jednak mogą wystąpić sytuacje, w których chcesz przechowywać dodatkowe informacje o użytkownikach.

 

Django pozwala rozszerzyć model User na kilka sposobów:

 

Rozszerzanie modelu User za pomocą linku One-To-One

 

Jednym ze sposobów rozszerzenia modelu User jest utworzenie nowego modelu z linkiem jeden do jednego do modelu User. Jest to użyteczne, jeśli chcesz przechowywać dodatkowe informacje o użytkownikach, ale nie musisz zmieniać wbudowanego zachowania uwierzytelniania Django.

 

# in your models.py
from django.contrib.auth.models import User
from django.db import models

class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    bio = models.TextField(blank=True)
    location = models.CharField(max_length=30, blank=True)

 

W tym przykładzie dodaliśmy pole bio i location do każdego użytkownika. Możesz uzyskać dostęp do tych pól za pomocą atrybutu user.profile.

 

Zastępowanie podstawowego modelu User

 

Jeśli musisz zmienić bardziej fundamentalne zachowanie modelu User, takie jak pola używane do uwierzytelniania, możesz całkowicie zastąpić model User własnym modelem.

 

Aby to zrobić, musisz utworzyć model, który zawiera wszystkie niezbędne pola i metody do uwierzytelniania, a następnie ustawić ustawienie AUTH_USER_MODEL w ustawieniach projektu tak, aby wskazywało na swój niestandardowy model.

 

# in your models.py
from django.contrib.auth.models import AbstractUser

class CustomUser(AbstractUser):
    bio = models.TextField(blank=True)
    location = models.CharField(max_length=30, blank=True)

 

# in your settings.py
AUTH_USER_MODEL = 'myapp.CustomUser'

 

W tym przykładzie utworzyliśmy niestandardowy model użytkownika, który zawiera pola bio i location. Klasa bazowa AbstractUser zawiera podstawową implementację modelu User, w tym metody hashowanego hasła i tokenu.

 

Uwaga: Jeśli rozpoczynasz nowy projekt, łatwiej jest skonfigurować niestandardowy model użytkownika na początku. Zmiana modelu użytkownika w środku projektu może być bardziej skomplikowana, ponieważ będziesz musiał przeprowadzić migrację bazy danych do nowego modelu.

 

 

Zaawansowane tematy: Niestandardowe uwierzytelnianie i autoryzacja

 

Może wystąpić sytuacja, gdy wbudowane systemy uwierzytelniania i autoryzacji Django nie są wystarczające dla twoich potrzeb. W takich przypadkach możesz stworzyć niestandardowe backendy uwierzytelniania i uprawnienia.

 

Niestandardowe Backendy Uwierzytelniania

 

W Django backend uwierzytelniania to klasa, która uwierzytelnia zestaw danych uwierzytelniających. Django posiada wbudowany backend uwierzytelniania, który uwierzytelnia użytkowników na podstawie ich nazwy użytkownika i hasła, ale możesz stworzyć własny backend uwierzytelniania, jeśli potrzebujesz uwierzytelniania użytkowników w inny sposób.

 

Aby stworzyć niestandardowy backend uwierzytelniania, musisz utworzyć klasę, która zawiera metodę get_user(user_id) i metodę authenticate(request, **credentials). Następnie dodaj swój niestandardowy backend uwierzytelniania do ustawienia AUTHENTICATION_BACKENDS w ustawieniach twojego projektu.

 

Oto przykład niestandardowego backendu uwierzytelniania:

 

# in your backends.py
from django.contrib.auth.backends import ModelBackend
from django.contrib.auth import get_user_model

class EmailBackend(ModelBackend):
    def authenticate(self, request, username=None, password=None, **kwargs):
        UserModel = get_user_model()
        try:
            user = UserModel.objects.get(email=username)
        except UserModel.DoesNotExist:
            return None

        if user.check_password(password):
            return user

    def get_user(self, user_id):
        UserModel = get_user_model()
        try:
            return UserModel.objects.get(pk=user_id)
        except UserModel.DoesNotExist:
            return None
# in your settings.py
AUTHENTICATION_BACKENDS = ['path.to.your.EmailBackend', 'django.contrib.auth.backends.ModelBackend']

 

W tym przykładzie stworzyliśmy niestandardowy backend uwierzytelniania, który uwierzytelnia użytkowników na podstawie ich emaila i hasła, a nie nazwy użytkownika i hasła.

 

Niestandardowe uprawnienia

 

W Django uprawnienie to wartość boolean określająca, czy użytkownik może wykonać daną akcję. Domyślnie Django zapewnia uprawnienia do dodawania, zmieniania i usuwania instancji modelu, ale możesz stworzyć własne niestandardowe uprawnienia, jeśli potrzebujesz.

 

Aby utworzyć niestandardowe uprawnienie, musisz dodać opcję permissions do klasy Meta swojego modelu. Następnie możesz sprawdzić uprawnienie w swoich widokach za pomocą metody user.has_perm().

 

Oto przykład niestandardowego uprawnienia:

 

# in your models.py
class Book(models.Model):
    # fields...

    class Meta:
        permissions = [
            ("can_edit_publish_date", "Can edit publish date"),
        ]

 

# in your views.py
def edit_publish_date(request, book_id):
    book = get_object_or_404(Book, id=book_id)

    if request.user.has_perm('library.can_edit_publish_date'):
        # The user can edit the publish date
    else:
        # The user cannot edit the publish date

 

W tym przykładzie utworzyliśmy niestandardowe uprawnienie, które pozwala użytkownikowi edytować datę publikacji książki.

 

 

Podsumowanie

 

W tym artykule omówiliśmy potężne funkcje zarządzania użytkownikami w Django, w tym wbudowane systemy uwierzytelniania i autoryzacji, model User, a nawet sposób tworzenia niestandardowych backendów uwierzytelniania i uprawnień.

 

Uwierzytelnianie i autoryzacja są kluczowymi aspektami tworzenia stron internetowych, zapewniając, że użytkownicy są tymi, za kogo się podają, i że mają dostęp tylko do tych obszarów i funkcji twojej strony, które zamierzasz udostępnić. Na szczęście Django zapewnia solidny system do obsługi tych funkcjonalności, co pozwala ci skupić się bardziej na unikalnych funkcjach twojej aplikacji, a nie na szczegółach bezpiecznego zarządzania użytkownikami.

 

W Django proces rejestrowania, uwierzytelniania i zarządzania użytkownikami został zabstractowany w sposób spójny i prosty w użyciu, ale na tyle elastyczny, aby sprostać bardziej zaawansowanym lub specyficznym przypadkom użycia.

 

Pamiętaj jednak, że bezpieczeństwo to obszerny temat. Ten post omówił podstawy i powinien służyć jako solidne podstawy, ale pamiętaj, aby kontynuować badania nad najlepszymi praktykami i dokumentacją Django podczas implementacji własnego systemu zarządzania użytkownikami.

 

Pamiętaj, że zarządzanie użytkownikami to kluczowy aspekt twojej strony internetowej lub aplikacji i powinno być podejście do niego z troską. Korzystaj z istniejących narzędzi Django, ale nie bój się również je rozszerzać, aby spełnić swoje specyficzne potrzeby.

 

 

Dyskusja

Twój komentarz

Tagi