Django: prijava, odjava i zaštićene strane

Lekcija 7 od 9 · Python web: Django projekat

Za prijavu i odjavu ne pišemo pogled – Django ih ima gotove (LoginView, LogoutView). Dovoljno je uključiti njihove adrese i napraviti šablon. Zatim zaključavamo strane koje smeju da vide samo prijavljeni korisnici.

Pre nego što počneš: potrebno predznanje – registracija.
Kako da učiš: radi u svom projektu korak po korak i posle svake lekcije proveri da li server radi; zadatak na kraju prvo uradi sam/a. Kod je za Django 5.2 (LTS) i Python 3.12+; svaki deo upiši u fajl naveden u komentaru na vrhu primera.

Gotove adrese za naloge

Red path("nalozi/", include("django.contrib.auth.urls")) iz glavnog urls.py uključuje:

AdresaIme ruteŠta radi
/nalozi/login/loginforma za prijavu
/nalozi/logout/logoutodjava (samo POST)
/nalozi/password_change/password_changepromena lozinke
/nalozi/password_reset/password_resetzaboravljena lozinka (zahteva slanje email-a)

Kuda se ide posle prijave i odjave određuju LOGIN_REDIRECT_URL i LOGOUT_REDIRECT_URL iz lekcije 3; LOGIN_URL = "login" kaže kuda se šalje neprijavljen korisnik.

Šablon za prijavu

{# templates/registration/login.html – ovo ime i mesto traži Django-ov LoginView #}
{% extends "base.html" %}

{% block naslov %}Prijava – Logo Kreator{% endblock %}

{% block sadrzaj %}
<div class="container py-4" style="max-width: 420px">
  <h1 class="h3 mb-3">Prijava</h1>
  {% if form.non_field_errors %}
    <div class="alert alert-danger">Pogrešno korisničko ime ili lozinka.</div>
  {% endif %}
  <form method="post">
    {% csrf_token %}
    <div class="mb-3">
      <label for="id_username" class="form-label">Korisničko ime</label>
      <input type="text" name="username" id="id_username" class="form-control" required autofocus>
    </div>
    <div class="mb-3">
      <label for="id_password" class="form-label">Lozinka</label>
      <input type="password" name="password" id="id_password" class="form-control" required>
    </div>
    <input type="hidden" name="next" value="{{ next }}">
    <button class="btn btn-danger w-100">Prijavi se</button>
  </form>
  <p class="mt-3 small">Nemaš nalog? <a href="{% url 'registracija' %}">Registruj se</a>.</p>
</div>
{% endblock %}

LoginView traži šablon registration/login.html i šalje mu formu pod imenom form i adresu povratka next. Ako su podaci pogrešni, form.non_field_errors nije prazno. Poruka namerno ne kaže da li je pogrešno ime ili lozinka – tako napadač ne može da sazna koja korisnička imena postoje.

Odjava: zašto POST

Od Django-a 5.0 odjava radi samo na POST zahtev. Da je dovoljan link (GET), tuđa stranica bi mogla da te odjavi skrivenom slikom sa tom adresom (CSRF). Zato je u base.html odjava mala forma sa dugmetom:

<form method="post" action="{% url 'logout' %}" class="d-inline">
  {% csrf_token %}
  <button class="btn btn-link nav-link">Odjava ({{ user.username }})</button>
</form>

Stari primeri sa <a href="/logout/"> u novim verzijama vraćaju grešku 405 (Method Not Allowed).

Zaštićene strane

from django.contrib.auth.decorators import login_required

@login_required                     # neprijavljen korisnik ide na /nalozi/login/?next=/moji-logoi/
def moji_logoi(request):
    logoi = request.user.logoi.all()
    return render(request, "logoi/moji_logoi.html", {"logoi": logoi})
ProveromGdePrimer
@login_requiredpogledcela strana samo za prijavljene
request.user.is_authenticatedpogledisti pogled radi različito (generator: čuvanje samo za prijavljene)
{% if user.is_authenticated %}šablonšta se prikazuje u meniju
get_object_or_404(..., vlasnik=request.user)pogledkorisnik dobija samo svoje podatke (lekcija 8)
Važno: sakrivanje linka u šablonu nije zaštita – svako može da upiše adresu ručno. Proveru uvek radi i pogled.

Video: strana za prijavu

Napomena uz video: video je snimljen za prvu verziju projekta (starija verzija Django-a, Heroku). Ideje su iste, ali se kod iz ove lekcije razlikuje u detaljima – kada se razlikuju, važi kod sa ove strane.

U videu je pogled za prijavu napisan ručno (authenticate + login). To je dobro za razumevanje, ali gotov LoginView je kraći i sigurniji.

Zadaci za vežbu

Za svaki zadatak postoji primer, uputstvo i rešenje.

ZADATAK 01Težina: srednje

Strana „Moj profil“

Napravi zaštićenu stranu /nalozi/profil/ koja prikazuje korisničko ime, datum registracije, broj sačuvanih logoa i link za promenu lozinke.

Česte greške i saveti
  • Šablon za prijavu mora biti tačno templates/registration/login.html.
  • Odjava linkom (GET) u Django-u 5+ ne radi – koristi formu sa POST-om.
  • Ne prosleđuj next na tuđe sajtove – Django-ov LoginView to sam proverava, ručno napisan pogled mora i to da proveri.

Proveri znanje

Otvori kviz

Prijava i odjava

1. Zašto odjava u Django-u 5 radi samo POST zahtevom?



2. Šta radi @login_required?




3. Da li je dovoljno sakriti link u meniju da bi strana bila zaštićena?