803. Jak działa mechanizm sesji w Django? Sesje a autentykacja w Django/DRF.

Mechanizm sesji, wprowadzenie:

Bezstanowość HTTP:
    Protokół HTTP jest bezstanowy, co oznacza, że każde żądanie jest traktowane niezależnie od poprzednich.
    Mechanizm sesji pozwala na przechowywanie informacji między żądaniami.

Identyfikator sesji:
    Gdy użytkownik łączy się z aplikacją, Django generuje unikalny identyfikator sesji (session ID).
    Identyfikator ten jest przesyłany do przeglądarki użytkownika jako ciasteczko (sessionid).

Przechowywanie danych sesji:
    Dane sesji są przechowywane po stronie serwera (np. w bazie danych, plikach, cache), a przeglądarka przechowuje tylko identyfikator sesji.
    Django domyślnie korzysta z bazy danych do przechowywania sesji.

Konfiguracja sesji w Django, settings.py:
    SESSION_ENGINE = "django.contrib.sessions.backends.db"  # Domyślnie: przechowywanie w bazie danych
    SESSION_COOKIE_NAME = "sessionid"  # Nazwa ciasteczka sesji
    SESSION_COOKIE_AGE = 1209600  # Czas ważności ciasteczka (domyślnie: 2 tygodnie)
    SESSION_SAVE_EVERY_REQUEST = False  # Czy odnawiać czas ważności ciasteczka przy każdym żądaniu
    SESSION_EXPIRE_AT_BROWSER_CLOSE = False  # Czy sesja wygasa po zamknięciu przeglądarki

Wbudowane funkcje mechanizmu sesji:

# Zapisywanie danych do sesji:
    def set_session(request):
        request.session['user_id'] = 42
        request.session['username'] = 'john_doe'
        return HttpResponse("Sesja ustawiona!")

# Odczytywanie danych z sesji:
    def get_session(request):
        user_id = request.session.get('user_id')  # Zwraca None, jeśli brak klucza
        username = request.session.get('username', 'Anonim')
        return HttpResponse(f"Użytkownik: {username}, ID: {user_id}")

# Usuwanie danych z sesji:
    def delete_session(request):
        del request.session['user_id']  # Usuwa tylko jeden klucz
        request.session.flush()  # Usuwa całą sesję
        return HttpResponse("Sesja wyczyszczona!")

Mechanizm sesji / Django Login-Based Autentykacja:

W Django mechanizm sesji jest bezpośrednio zintegrowany z wbudowanymi funkcjami logowania (Login-Based Autentykacja).

Logowanie użytkownika:
    Widoki z modułu django.contrib.auth.views automatycznie zapisują dane użytkownika w sesji po pomyślnym logowaniu.
    Po zalogowaniu możesz uzyskać dostęp do danych użytkownika w widokach za pomocą request.user.

    # Przykład logowania:
    from django.contrib.auth import authenticate, login

    def login_view(request):
        username = request.POST['username']
        password = request.POST['password']
        user = authenticate(request, username=username, password=password)
        if user is not None:
            login(request, user)  # Ustawia dane użytkownika w sesji
            return HttpResponse("Zalogowano!")
        else:
            return HttpResponse("Niepoprawne dane logowania.")

    # Co robi funkcja login?
        - Django doda nagłówek Set-Cookie w odpowiedzi HTTP tylko wtedy, gdy funkcja login zostanie wywołana i user zostanie pomyślnie uwierzytelniony.
          Wtedy:
            - Tworzy lub aktualizuje sesję w bazie danych Django, przypisując do niej dane użytkownika (zwykle jego ID).
            - Generuje unikalny identyfikator sesji (tzw. klucz sesji).
            - Ustawia ciasteczko sessionid w odpowiedzi HTTP przy użyciu nagłówka Set-Cookie.
            - Set-Cookie: sessionid=<unikalny_klucz_sesji> Path=/; HttpOnly; Secure; SameSite=Lax
        - Jeśli użytkownik nie zostanie uwierzytelniony (np. nieprawidłowe dane logowania), Set-Cookie nie zostanie wysłany.


    # Wylogowanie użytkownika:
    # Wylogowanie usuwa dane użytkownika z sesji, przykład:

    from django.contrib.auth import logout

    def logout_view(request):
        logout(request)
        return HttpResponse("Wylogowano!")


    # Co dokładnie się dzieje w logout?
      - Metoda logout usuwa klucz sesji użytkownika (domyślnie tabela django_session) i odłącza bieżącego użytkownika od requestu.
      - Po wywołaniu: request.user staje się instancją klasy AnonymousUser
      Przykład nagłówka, po wylogowaniu:
      - Set-Cookie: sessionid=; expires=Thu, 01 Jan 1970 00:00:00 GMT; Max-Age=0; Path=/; SameSite=Lax; HttpOnly


Mechanizm sesji / DRF Login-Based Autentykacja:

Czym jest tryb SessionAuthentication w DRF?
    To inaczej tzw. Autentykacja Login-Based. SessionAuthentication wykorzystuje ciasteczko sesji (sessionid) do identyfikacji użytkownika.
    Użytkownik musi być zalogowany w Django, aby wykonywać uwierzytelnione żądania w DRF.

    # Konfiguracja w DRF, settings.py:

    REST_FRAMEWORK = {
        "DEFAULT_AUTHENTICATION_CLASSES": [
            "rest_framework.authentication.SessionAuthentication",
        ],
    }

    # do implementacji punkty końcowe obsługujące proces logowania:
      - np. login/, logout/, (register/)

Mechanizm sesji w Django:
    - pozwala łatwo implementować funkcje takie jak logowanie, zapisywanie danych koszyka czy personalizowane ustawienia użytkownika.
W DRF, klasa SessionAuthentication rozszerza ten mechanizm na API, ułatwiając autentykację w aplikacjach hybrydowych.