forked from nette/docs
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathauthentication.texy
180 lines (122 loc) · 7.14 KB
/
authentication.texy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
Preverjanje pristnosti
**********************
Nette vam ponuja smernice za programiranje avtentikacije na vaši strani, vendar vas ne sili, da to storite na kakršen koli poseben način. Izvedba je odvisna od vas. Nette ima vmesnik `Nette\Security\Authenticator`, ki vas prisili, da implementirate le eno metodo, imenovano `authenticate`, ki poišče uporabnika, kakorkoli želite.
Obstaja veliko načinov, kako se lahko uporabnik avtentificira. Najpogostejši način je *avtentikacija na podlagi gesla* (uporabnik navede svoje ime ali e-pošto in geslo), vendar obstajajo tudi drugi načini. Morda poznate gumbe "Prijava s Facebookom" na številnih spletnih mestih ali prijavo prek Googla/Twitterja/GitHuba ali katerega koli drugega spletnega mesta. Z Nette lahko uporabite kateri koli način avtentikacije, ki ga želite, lahko pa jih tudi kombinirate. Vse je odvisno od vas.
Običajno bi napisali svoj avtentifikator, vendar bomo za ta preprost mali blog uporabili vgrajeni avtentifikator, ki avtentificira na podlagi gesla in uporabniškega imena, shranjenega v konfiguracijski datoteki. To je dobro za namene testiranja. Zato bomo v konfiguracijsko datoteko `config/common.neon` dodali naslednji razdelek *security*:
```neon .{file:config/common.neon}
security:
users:
admin: secret # uporabnik 'admin', geslo 'secret'
```
Nette bo samodejno ustvaril storitev v vsebniku DI.
Obrazec za prijavo .[#toc-sign-in-form]
=======================================
Zdaj imamo pripravljen zaledni del avtentikacije, zagotoviti pa moramo uporabniški vmesnik, prek katerega se bo uporabnik prijavil. Ustvarimo nov predstavnik z imenom *SignPresenter*, ki bo
- prikazal obrazec za prijavo (ki bo zahteval uporabniško ime in geslo)
- preveril pristnost uporabnika, ko bo obrazec oddan
- zagotovil dejanje odjave
Začnimo z obrazcem za prijavo. Že veste, kako delujejo obrazci v predstavitvenem programu. Ustvarite `SignPresenter` in metodo `createComponentSignInForm`. Izgledati morata takole:
```php .{file:app/UI/Sign/SignPresenter.php}
<?php
namespace App\UI\Sign;
use Nette;
use Nette\Application\UI\Form;
final class SignPresenter extends Nette\Application\UI\Presenter
{
protected function createComponentSignInForm(): Form
{
$form = new Form;
$form->addText('username', 'Username:')
->setRequired('Please enter your username.');
$form->addPassword('password', 'Password:')
->setRequired('Please enter your password.');
$form->addSubmit('send', 'Sign in');
$form->onSuccess[] = $this->signInFormSucceeded(...);
return $form;
}
}
```
Na voljo je vnos za uporabniško ime in geslo.
Predloga .[#toc-template]
-------------------------
Obrazec bo prikazan v predlogi `in.latte`
```latte .{file:app/UI/Sign/in.latte}
{block content}
<h1 n:block=title>Sign in</h1>
{control signInForm}
```
Obvladovalnik prijave .[#toc-login-handler]
-------------------------------------------
Dodamo tudi *obdelovalnik obrazca* za prijavo uporabnika, ki se sproži takoj po oddaji obrazca.
Obvladovalnik bo samo prevzel uporabniško ime in geslo, ki ju je vnesel uporabnik, ter ju posredoval prej opredeljenemu avtentifikatorju. Ko se uporabnik prijavi, ga bomo preusmerili na domačo stran.
```php .{file:app/UI/Sign/SignPresenter.php}
private function signInFormSucceeded(Form $form, \stdClass $data): void
{
try {
$this->getUser()->login($data->username, $data->password);
$this->redirect('Home:');
} catch (Nette\Security\AuthenticationException $e) {
$form->addError('Incorrect username or password.');
}
}
```
Metoda [User::login() |api:Nette\Security\User::login()] mora zavreči izjemo, če se uporabniško ime ali geslo ne ujemata s tistima, ki smo ju opredelili prej. Kot že vemo, bi to povzročilo rdeči zaslon [Tracy |tracy:] ali, v produkcijskem načinu, sporočilo, ki obvešča o notranji napaki strežnika. To nam ne bi bilo všeč. Zato ujamemo izjemo in v obrazec dodamo lepo in prijazno sporočilo o napaki.
Ko se v obrazcu pojavi napaka, se stran z obrazcem ponovno prikaže, nad obrazcem pa je lepo sporočilo, ki uporabnika obvesti, da je vnesel napačno uporabniško ime ali geslo.
Varnost predstavnikov .[#toc-security-of-presenters]
====================================================
Zagotovili bomo obrazec za dodajanje in urejanje objav. Opredeljen je v predstavniku `EditPresenter`. Cilj je preprečiti dostop do strani neprijavljenim uporabnikom.
Ustvarimo metodo `startup()`, ki se zažene takoj na začetku [življenjskega cikla predstavnika |application:presenters#life-cycle-of-presenter]. Ta uporabnike, ki niso prijavljeni, preusmeri na obrazec za prijavo.
```php .{file:app/UI/Edit/EditPresenter.php}
public function startup(): void
{
parent::startup();
if (!$this->getUser()->isLoggedIn()) {
$this->redirect('Sign:in');
}
}
```
Skrij povezave .[#toc-hide-links]
---------------------------------
Uporabnik brez avtentikacije ne more več videti strani *ustvari* in *revidiraj*, še vedno pa lahko vidi povezave, ki kažejo nanju. Skrijmo tudi te. Ena takšnih povezav je na naslovu `app/UI/Home/default.latte`, vidna pa mora biti le, če je uporabnik prijavljen.
Skrijemo jo lahko z uporabo *n:atributa*, imenovanega `n:if`. Če je izjava v njem `false`, se celotna `<a>` oznaka in njena vsebina ne bosta prikazani:
```latte
<a n:href="Edit:create" n:if="$user->isLoggedIn()">Create post</a>
```
To je bližnjica za (ne zamenjujte s `tag-if`):
```latte
{if $user->isLoggedIn()}<a n:href="Edit:create">Create post</a>{/if}
```
Na podoben način morate skriti povezavo za urejanje, ki se nahaja na naslovu `app/UI/Post/show.latte`.
Povezava na prijavni obrazec .[#toc-login-form-link]
====================================================
Hej, ampak kako pridemo do prijavne strani? Ni nobene povezave, ki bi kazala nanjo. Dodajmo jo v datoteko predloge `@layout.latte`. Poskusi najti lepo mesto, lahko je kjerkoli, kjer ti je najbolj všeč.
```latte .{file:app/UI/@layout.latte}
...
<ul class="navig">
<li><a n:href="Home:">Home</a></li>
{if $user->isLoggedIn()}
<li><a n:href="Sign:out">Sign out</a></li>
{else}
<li><a n:href="Sign:in">Sign in</a></li>
{/if}
</ul>
...
```
Če uporabnik še ni prijavljen, bomo prikazali povezavo "Prijavite se". V nasprotnem primeru bomo prikazali povezavo "Odjavi se". To dejanje dodamo v SignPresenter.
Akcija odjave je videti takole, in ker uporabnika takoj preusmerimo, ne potrebujemo predloge za prikaz.
```php .{file:app/UI/Sign/SignPresenter.php}
public function actionOut(): void
{
$this->getUser()->logout();
$this->flashMessage('You have been signed out.');
$this->redirect('Home:');
}
```
Samo pokliče metodo `logout()` in nato uporabniku prikaže lepo sporočilo.
Povzetek .[#toc-summary]
========================
Imamo povezavo za prijavo in tudi za odjavo uporabnika. Za preverjanje pristnosti smo uporabili vgrajeni avtentifikator, podatki za prijavo pa so v konfiguracijski datoteki, saj gre za preprosto testno aplikacijo. Zavarovali smo tudi obrazce za urejanje, tako da lahko samo prijavljeni uporabniki dodajajo in urejajo objave.
.[note]
Tukaj lahko preberete več o [prijavi |security:authentication] in [avtorizaciji |security:authorization] [uporabnikov |security:authentication].
{{priority: -1}}
{{sitename: Nette Quickstart}}