Na začátek si neodpustím terminologickou poznámku: autentizace (někdy psáno též jako autentikace, případně autentifikace) je proces ověření identity uživatele. Pomocí ní tedy zjistíme, že u počítač pravděpodobně sedí Alice a ne třeba Bob, protože je aktuální návštěvník přihlášen pomocí Aliciných uživatelských údajů. Autorizace se oproti tomu stará o kontrolu oprávnění, tedy aby přístup měli jenom ti uživatelé, kterým jsme ho povolili.
Modul django.contrib.auth
Aplikaci zajišťující autentizaci a autorizaci můžeme nalézt v modulu Djanga django.contrib.auth
. Hlavní součástí je model User
, který představuje přihlášeného uživatele. Nepřihlášení uživatelé jsou reprezentováni odvozeným modelem AnonymousUser
. Ať už je uživatel přihlášen nebo ne, můžeme k jeho modelu přistupovat v pohledech pomocí objektu request.user
a v šablonách přes proměnnou {{ user }}
. Instance modelu uživatele obsahuje několik zajímavých atributů:
user.username
: uživatelské jménouser.first_name
: křestní jménouser.last_name
: příjmeníuser.email
: e-mailuser.is_staff
: příznak, zda má uživatel povolený vstup do administraceuser.is_active
: příznak, zda je uživatel aktivní
Kromě atributů máme k dispozici několik důležitých metod:
user.is_authenticated()
: zkontroluje, zda je uživatel přihlášenuser.get_full_name()
: celé jméno uživateleuser.set_password()
: nastaví uživatelovo heslouser.check_password()
: ověří, jestli se zadané heslo shoduje s heslem uživatele
Toto není vyčerpávající seznam, popis mnoha dalších atributů a metod lze najít v dokumentaci a některé si ještě představíme později.
Protože je uživatel reprezentován modelem, zacházíme s ním podobně jako s ostatními databázovými modely. Můžeme přidávat nové uživatelské účty, odstraňovat je a upravovat uživatelské údaje. Vytváření nového uživatelského účtu nám může usnadnit funkce create_user
:
>>> from django.contrib.auth.models import User
>>> user = User.objects.create_user('honza', 'honza@example.com', 'honzovoheslo')
>>> user.first_name = 'Jan'
>>> user.last_name = 'Novák'
>>> user.save()
>>> user
<User: honza>
>>> user.is_staff
False
>>> user.password
'sha1$32f0e$c445ff000ed85dff88f32f874d7021bee2fe1cc4'
>>> user.check_password('honzovoheslo')
True
>>> user.check_password('jinéheslo')
False
set_password
nebo check_password
.Přihlašování a odhlašování
Identita návštěvníka se dá ověřit pomocí funkce authenticate
, která vrátí objekt uživatele v případě úspěšného ověření nebo prázdný objekt pokud se ověření nezdaří. Poté uživatele můžeme přihlásit pomocí metody login
a kdykoliv později odhlásit pomocí metody logout
. Místo toho, abychom se pustili do vytváření pohledů pro přihlašování a odhlašování, využijeme generické pohledy, které byly pro tento účel vytvořeny. Otevřeme si tedy soubor urls.py
a připíšeme na konec několik řádků kódu:
urlpatterns += patterns('', # ... (r'^accounts/login/$', 'django.contrib.auth.views.login', {'template_name': 'login.html'}), (r'^accounts/logout/$', 'django.contrib.auth.views.logout', {'template_name': 'logout.html'}), )
Cesty /accounts/login/
a /accounts/logout/
jsou výchozí a dají se přenastavit v souboru settings.py
pomocí konstant LOGIN_URL a LOGOUT_URL. Klíčem template_name
jsem si vybral jiné umístění šablony, ve výchozím nastavení jsou umístěny v podadresáři registration
. Šablona pro přihlašování (soubor templates/login.html
) může vypadat třeba takto:
{% extends "base.html" %} {% block content %} <h1>{% block title %}Přihlášení{% endblock %}</h1> {% if form.errors %} <p>Špatně zadané uživatelské jméno nebo heslo. Zkuste se prosím přihlásit znovu.</p> {% endif %} <form action="." method="POST"> <table> {% include "form.html" %} <tr> <td></td> <td> <input type="submit" value="Přihlásit se"> <input type="hidden" name="next" value="{{ next }}"> </td> </tr> </table> </form> {% endblock %}
V případě neúspěšného přihlášení vypíšeme na sedmém řádku chybovou hlášku. Na dvanáctém řádku je využita šablona pro výpis formuláře z minulého dílu. Sedmnáctý řádek obsahuje skrytou hodnotu formuláře next
, což je adresa stránky, na kterou budeme po přihlášení přesměrováni. Pokud není hodnota next
zadána, standardně se přejde na /accounts/profile/
(dá se přenastavit pomocí konstanty LOGIN_REDIRECT_URL).
Odhlašovací šablona (templates/logout.html
) bude oproti té přihlašovací jednodušší:
{% extends "base.html" %} {% block content %} <h1>{% block title %}Odhlášeno{% endblock %}</h1> <p>Byl(a) jste odhlášen(a). Nashle příště!</p> {% endblock %}
Uživatelský profil
Na začátku jsme se dozvěděli, že model uživatele obsahuje jeho jméno, příjmení a e-mail. Ale co když chceme k uživatelskému účtu připojit dodatečné informace? Stačí rozšířit jeho model pomocí tzv. profilu. Otevřeme si soubor video_store/models.py
a přidáme tento kód:
from django.contrib.auth.models import User class Profile(models.Model): user = models.OneToOneField(User, verbose_name='Uživatel') info = models.TextField('Informace', blank=True) def __unicode__(self): return self.user.username class Meta: verbose_name = 'profil' verbose_name_plural = 'profily'
Založili jsme si nový model, který k modelu uživatele připojí textové pole, kam můžeme poznamenat jakékoliv další údaje. Na čtvrtém řádku je použit atribut typu OneToOneField
, což je obdoba unikátního cizího klíče (ForeignKey
s parametrem unique=True
). Takováto vazba nám zaručí, že jeden uživatel bude mít právě jeden profil (ne více).
Když máme definovaný model, sesynchronizujeme ho s databází (python manage.py syncdb
) a vytvoříme pro něj formulář. V tomto případě ho zčásti můžeme vygenerovat. Otevřeme si soubor video_store/forms.py
a vložíme do něj následující kód:
from django.contrib.auth.models import User class ProfileForm(forms.ModelForm): info = forms.CharField(label='Informace', widget=forms.Textarea, required=False) password1 = forms.CharField(label='Heslo', widget=forms.PasswordInput, required=False) password2 = forms.CharField(label='Heslo znovu', widget=forms.PasswordInput, required=False) class Meta: model = User fields = ('first_name', 'last_name', 'email') def clean_password2(self): if self.cleaned_data.get('password1') != self.cleaned_data['password2']: raise forms.ValidationError('Zadaná hesla se liší.') return self.cleaned_data['password2']
Můžeme zde vidět dvě nové věci. První je, že formulář neodvozujeme od třídy forms.Form
, ale forms.ModelForm
. Tato třída slouží pro generování formulářů z modelů. V podtřídě Meta
specifikujeme atributem model
, ze kterého modelu se má formulář generovat. Pokud neuvedeme výčet atributů modelu, které se mají použít, pomocí meta atributů fields
nebo exclude
, jsou pro generování použity všechny atributy. Druhá nová věc je metoda clean_password2
. Máme možnost si definovat vlastní validaci určitého formulářového políčka pomocí metody pojmenované clean_políčko
. Pokud uživatelský vstup nevyhovuje, vyhodí se výjimka forms.ValidationError
a u daného políčka se vypíše uživateli chybová hláška. V tomto případě kontrolujeme, zda jsou zadaná hesla stejná.
Ještě musíme provázat uživatelský model s profilem. Na to má Django vyhrazenou konstantu AUTH_PROFILE_MODULE
, která se tradičně nachází v souboru settings.py
. Stačí do něj připsat tento řádek:
AUTH_PROFILE_MODULE = 'video_store.Profile'
Jakmile má tato konstanta přiřazenou cestu k našemu modelu, stačí u objektu uživatele zavolat metodu get_profile
. Tato metoda vrací profil daného uživatele nebo vyvolává výjimku Profile.DoesNotExist
. Vytvoříme si v souboru video_store/views.py
pohled, ve kterém využijeme tohoto propojení:
from models import Profile from forms import ProfileForm from django.contrib.auth.decorators import login_required @login_required def profile(request, saved): try: profile = request.user.get_profile() except Profile.DoesNotExist: profile = Profile(user=request.user) if request.method == 'POST': form = ProfileForm(request.POST) if form.is_valid(): request.user.first_name = form.cleaned_data['first_name'] request.user.last_name = form.cleaned_data['last_name'] request.user.email = form.cleaned_data['email'] if len(form.cleaned_data['password1']) > 0: request.user.set_password(form.cleaned_data['password1']) request.user.save() profile.info = form.cleaned_data['info'] profile.save() return HttpResponseRedirect('/accounts/profile/saved/') else: form = ProfileForm(initial={'first_name': request.user.first_name, 'last_name': request.user.last_name, 'email': request.user.email, 'info': profile.info, }) return render_to_response('profile.html', {'form': form, 'saved': saved}, context_instance=RequestContext(request))
Před samotnou definicí pohledu je podivný kód @login_required
, kterému se říká dekorátor. Je to vlastně funkce, která obalí jinou funkci, jenom je zde použit zkrácený zápis, který se používá v Pythonu 2.4 a novějším. Tento dekorátor zamezí přístup všem nepřihlášeným uživatelům a přesměruje je na stránku s přihlášením. V samotném pohledu zavoláme již zmíněnou metodu get_profile
(řádek 8) a v případě, že uživatel nemá přiřazený profil, založíme mu nový (řádek 10). Do databáze ukládáme zvlášť objekt uživatele a zvlášť jeho profil. Pokud uživatel vyplnil kolonku s heslem (řádek 20), změníme mu ho. Všimněte si, že zobrazený formulář (řádek 30) má některá políčka již předvyplněná.
K pohledu je potřeba vytvořit odpovídající šablonu. V ní stačí zobrazit formulář a v případě, že došlo k jeho úspěšnému uložení, vypsat potvrzující hlášku. Šablonu uložíme do souboru templates/profile.html
:
{% extends "base.html" %} {% block content %} <h1>{% block title %}Uživatelský profil{% endblock %}</h1> {% if saved %} <p>Profil byl upraven.</p> {% endif %} <form action="." method="POST"> <table> {% include "form.html" %} <tr> <td></td> <td><input type="submit" value="Upravit"></td> </tr> </table> </form> {% endblock %}
A nakonec si můžeme v souboru templates/base.html
rozšířit část <div id="menu">
o zobrazování informací o aktuálně přihlášeném uživateli:
{% if user.is_authenticated %} <ul id="user"> <li>Přihlášen: <a href="/accounts/profile/">{{ user }}</a></li> {% if user.is_staff %} <li><a href="/admin/">Administrace</a></li> {% endif %} <li><a href="/accounts/logout/">Odhlásit</a></li> </ul> {% endif %}
Související odkazy
- Autentizace na Djangoproject.com
- Čtrnáctá kapitola v The Definitive Guide to Django
- Ukázkový příklad ke stažení.
V dalším díle se budeme zabývat nahráváním souborů do aplikace.
Přehled komentářů