-
-
Notifications
You must be signed in to change notification settings - Fork 277
Expand file tree
/
Copy pathauthentication.texy
More file actions
179 lines (121 loc) · 8.7 KB
/
authentication.texy
File metadata and controls
179 lines (121 loc) · 8.7 KB
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
認証
*************
Netteは、私たちのサイトで認証をプログラムする方法を提供しますが、何も強制しません。実装は私たち次第です。Netteには`Nette\Security\Authenticator`インターフェースが含まれており、これは`authenticate`という1つのメソッドのみを要求します。このメソッドは、私たちが望む任意の方法でユーザーを検証します。
ユーザーを認証する方法はたくさんあります。最も一般的な認証方法はパスワードによるものです(ユーザーは名前またはメールアドレスとパスワードを提供します)が、他の方法もあります。一部のサイトで「Facebookでログイン」ボタンやGoogle/Twitter/GitHubによるログインを見たことがあるかもしれません。Netteを使用すると、任意のログイン方法を持つことができ、それらを組み合わせることもできます。実装は開発者に委ねられています。
通常は独自の認証システムを作成しますが、このシンプルな小さなブログでは、設定ファイルに保存されているパスワードとユーザー名に基づいてログインする組み込みの認証システムを使用します。これはテスト目的に適しています。したがって、設定ファイル`config/common.neon`に次の*security*セクションを追加します。
```neon .{file:config/common.neon}
security:
users:
admin: secret # ユーザー 'admin', パスワード 'secret'
```
NetteはDIコンテナに自動的にサービスを作成します。
ログインフォーム
========
これで認証の準備が整い、ログイン用のユーザーインターフェースを準備する必要があります。*SignPresenter*という名前の新しいPresenterを作成しましょう。これは次のことを行います。
- ログインフォーム(ログイン名とパスワード付き)を表示する
- フォーム送信後、ユーザーを認証する
- ログアウトオプションを提供する
ログインフォームから始めましょう。Presenterでフォームがどのように機能するかはすでに知っています。したがって、Presenter `SignPresenter`を作成し、メソッド`createComponentSignInForm`を記述します。次のようになります。
```php .{file:app/Presentation/Sign/SignPresenter.php}
<?php
namespace App\Presentation\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', 'ユーザー名:')
->setRequired('ユーザー名を入力してください。');
$form->addPassword('password', 'パスワード:')
->setRequired('パスワードを入力してください。');
$form->addSubmit('send', 'ログイン');
$form->onSuccess[] = $this->signInFormSucceeded(...);
return $form;
}
}
```
ユーザー名とパスワードのフィールドがあります。
テンプレート
------
フォームはテンプレート`in.latte`でレンダリングされます。
```latte .{file:app/Presentation/Sign/in.latte}
{block content}
<h1 n:block=title>ログイン</h1>
{control signInForm}
```
ログインコールバック
----------
次に、フォームが正常に送信された直後に呼び出されるユーザーログイン用のコールバックを追加します。
コールバックは、ユーザーが入力したユーザー名とパスワードを受け取り、それらを認証システムに渡すだけです。ログイン後、ホームページにリダイレクトします。
```php .{file:app/Presentation/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('ユーザー名またはパスワードが正しくありません。');
}
}
```
メソッド[User::login() |api:Nette\Security\User::login()]は、ユーザー名とパスワードが設定ファイルの情報と一致しない場合に例外をスローします。すでに知っているように、これにより赤いエラーページが表示されるか、本番モードではサーバーエラーを通知するメッセージが表示される可能性があります。しかし、それは望ましくありません。したがって、この例外をキャッチし、フォームにわかりやすい、ユーザーフレンドリーなエラーメッセージを渡します。
フォームでエラーが発生すると、フォームのあるページが再描画され、フォームの上に、ユーザーが間違ったログイン名またはパスワードを入力したことを通知するわかりやすいメッセージが表示されます。
Presenterの保護
============
投稿を追加および編集するためのフォームを保護します。これはPresenter `EditPresenter`で定義されています。目標は、ログインしていないユーザーがページにアクセスできないようにすることです。
[Presenterのライフサイクル |application:presenters#Presenterのライフサイクル]の開始直後に実行される`startup()`メソッドを作成します。これにより、ログインしていないユーザーがログインフォームにリダイレクトされます。
```php .{file:app/Presentation/Edit/EditPresenter.php}
public function startup(): void
{
parent::startup();
if (!$this->getUser()->isLoggedIn()) {
$this->redirect('Sign:in');
}
}
```
リンクの非表示
-------
認証されていないユーザーは、*create*ページや*edit*ページを表示できなくなりましたが、それらへのリンクはまだ表示されます。これらも非表示にする必要があります。そのようなリンクの1つはテンプレート`app/Presentation/Home/default.latte`にあり、ログインしているユーザーのみが表示できるようにする必要があります。
*n:属性* `n:if`を使用して非表示にできます。この条件が`false`の場合、コンテンツを含む`<a>`タグ全体が非表示のままになります。
```latte
<a n:href="Edit:create" n:if="$user->isLoggedIn()">投稿を作成</a>
```
これは、次の記述の省略形です(`tag-if`と混同しないでください):
```latte
{if $user->isLoggedIn()}<a n:href="Edit:create">投稿を作成</a>{/if}
```
同様の方法で、テンプレート`app/Presentation/Post/show.latte`のリンクも非表示にします。
ログインリンク
=======
実際にログインページにアクセスするにはどうすればよいでしょうか?そこにつながるリンクはありません。それでは、テンプレート`@layout.latte`に追加しましょう。適切な場所を見つけてみてください - ほとんどどこでもかまいません。
```latte .{file:app/Presentation/@layout.latte}
...
<ul class="navig">
<li><a n:href="Home:">記事</a></li>
{if $user->isLoggedIn()}
<li><a n:href="Sign:out">ログアウト</a></li>
{else}
<li><a n:href="Sign:in">ログイン</a></li>
{/if}
</ul>
...
```
ユーザーがログインしていない場合は、「ログイン」リンクが表示されます。それ以外の場合は、「ログアウト」リンクが表示されます。このアクションも`SignPresenter`に追加します。
ログアウト後すぐにユーザーをリダイレクトするため、テンプレートは必要ありません。ログアウトは次のようになります。
```php .{file:app/Presentation/Sign/SignPresenter.php}
public function actionOut(): void
{
$this->getUser()->logout();
$this->flashMessage('ログアウトしました。');
$this->redirect('Home:');
}
```
`logout()`メソッドが呼び出され、その後、ログアウトが成功したことを確認するわかりやすいメッセージが表示されます。
まとめ
===
ログインとユーザーログアウトのためのリンクがあります。検証には組み込みの認証システムを使用し、ログイン情報は設定ファイルにあります。これは簡単なテストアプリケーションであるためです。また、編集フォームも保護したので、ログインしているユーザーのみが投稿を追加および編集できます。
.[note]
ここでは、[ユーザーログイン |security:authentication]と[権限の検証 |security:authorization]について詳しく読むことができます。
{{priority: -1}}