# 權限驗證
Nette為您提供了如何在頁面上對身份驗證進行編程的指導,但不強迫您以任何特定方式進行驗證。 實現取決于你。 Nette有一個Nette \ Security \ IAuthenticator接口,強制您只實現一個名為authenticate的方法,它找到用戶無論你想要做什么。
有很多方式如何用戶可以驗證自己。 最常見的方法是基于密碼的身份驗證(用戶提供其姓名或電子郵件和密碼),但也有其他方法。 您可能熟悉許多網站上的“使用Facebook登錄”按鈕,或通過Google / Twitter / GitHub或任何其他網站登錄。 有了Nette,你可以有任何你想要的驗證方法,或者你可以組合它們。 隨你便。
通常你會編寫自己的認證器,但對于這個簡單的小博客,我們可以使用SimpleAuthenticator,它與Nette捆綁在一起。 它提供基于密碼的身份驗證,用戶名和密碼存儲在配置文件中。 在config.neon中添加安全部分(不要忘記更改密碼):
~~~
security:
users:
admin: secret # user 'admin', password 'secret'
~~~

Nette將自動在DI容器中創建一個名為authenticator的服務。
# 登錄表單
我們現在擁有身份驗證的后端部分,我們需要提供一個用戶界面,用戶將通過它登錄。讓我們創建一個名為SignPresenter的新控制器,他主要功能有以下
1、顯示登錄表單(要求輸入用戶名和密碼)
2、在表單提交時驗證用戶
3、提供注銷操作。
讓我們從登錄表單開始。 你已經知道表單在控制器中如何工作。 創建SignPresenter控制器并增加一個方法createComponentSignInForm。 它應該看起來像這樣:
~~~
<?php
namespace App\Presenters;
use Nette;
use Nette\Application\UI\Form;
class SignPresenter extends Nette\Application\UI\Presenter
{
protected function createComponentSignInForm()
{
$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;
}
~~~

現在有一個用戶名和密碼的輸入表單了。
# 視圖
表單將顯示在模板app / presenters / templates / Sign / in.latte中
~~~
{block content}
<h1 n:block=title>Sign in</h1>
{control signInForm}
~~~

# 登錄處理程序
我們還添加了一個用于登錄用戶的表單處理程序,該表單處理程序在表單提交后立即調用。
處理程序將只接受用戶輸入的用戶名和密碼,并將其傳遞給之前定義的認證器。 用戶登錄后,我們會將他重定向到首頁。我們現在在SignPresenter.php控制器中增加以下方法。
~~~
public function signInFormSucceeded($form, $values)
{
try {
$this->getUser()->login($values->username, $values->password);
$this->redirect('Homepage:');
} catch (Nette\Security\AuthenticationException $e) {
$form->addError('Nesprávné p?ihla?ovací jméno nebo heslo.');
}
}
~~~
當用戶名或密碼與我們之前定義的不匹配時,User :: login()方法應該拋出異常。 正如我們已經知道的,這將導致Tracy的紅屏,或者,在生產模式下,通知內部服務器錯誤的消息。 我們不會喜歡。 這就是為什么我們捕獲異常,并添加一個漂亮和友好的錯誤消息到窗體。
當窗體中出現錯誤時,帶有窗體的頁面將被再次渲染,并且在窗體上方,會有一個很好的消息,通知用戶他們輸入了錯誤的用戶名或密碼。
# POST表單
首先,讓我們保證創建新帖子的形式。 它在PostPresenter中定義并在app / presenters / templates / Post / create.latte中呈現。 我們的第一個目標是不允許用戶在未登錄的情況下查看該頁面。
# 控制器視圖
讓我們創建一個動作方法actionCreate,它將用戶重定向到登錄形式,如果用戶沒有登錄,需要驗證。
~~~
public function actionCreate()
{
if (!$this->getUser()->isLoggedIn()) {
$this->redirect('Sign:in');
}
}
~~~
我們還應該保護編輯視圖,所以只需添加那些三行。
~~~
public function actionEdit($postId)
{
if (!$this->getUser()->isLoggedIn()) {
$this->redirect('Sign:in');
}
~~~

# 隱藏鏈接
未經身份驗證的用戶看不到創建或編輯頁面,但他仍然可以看到指向他們的鏈接。 讓我們隱藏這些鏈接。 在app / presenters / templates / Homepage / default.latte中一個這樣的鏈接,并且只有在用戶登錄時才可見。
我們可以使用名為n:if的n:標注隱藏它。 如果其中的語句為false,則將不顯示整個<a>標記及其內容
~~~
<a n:href="Post:create" n:if="$user->loggedIn">Create post</a>
~~~
這是一個快捷方式(不要混淆標簽if)
~~~
{if $user->loggedIn}<a n:href="Post:create">Create post</a>{/if}
~~~
您應該以類似的方式隱藏位于app / presenters / templates / Post / show.latte中的編輯鏈接。
# 表單處理程序
最后,最重要的是保護表單處理程序。 因為組件是可重用的,它們可以在幾個視圖中呈現。 因為它們可以在幾個視圖中渲染,它們也可以從任何這樣的視圖提交,甚至是不真正存在的視圖。 這意味著,即使視圖創建沒有呈現,通過調整url,用戶仍然可以提交表單(和添加/編輯帖子)。
它可以防止與一個簡單的,我們將添加在postFormSucceeded的開始
~~~
public function postFormSucceeded($form)
{
if (!$this->getUser()->isLoggedIn()) {
$this->error('You need to log in to create or edit posts');
}
~~~
這很簡單,但你永遠不會忘記這樣做,因為它是非常重要保護你的應用程序。
# 登錄表單鏈接
嘿,但是我們怎么進入登錄頁面? 沒有指向它的鏈接。 讓我們在app/presenters/templates/@layout.latte模板文件中添加一個。
~~~
<ul class="navig">
<li><a n:href="Homepage:">Homepage</a></li>
{if $user->loggedIn}
<li><a n:href="Sign:out">Sign out</a></li>
{else}
<li><a n:href="Sign:in">Sign in</a></li>
{/if}
</ul>
~~~
如果用戶尚未登錄,我們將顯示“登錄”鏈接。 否則,我們將顯示“退出”鏈接。 我們在SignPresenter中添加注銷操作。
注銷操作看起來像這樣,并且因為我們立即重定向用戶,所以不需要視圖模板。
~~~
public function actionOut()
{
$this->getUser()->logout();
$this->flashMessage('You have been signed out.');
$this->redirect('Homepage:');
}
~~~
它只是調用logout()方法,然后向用戶顯示一個很好的消息。
有一個登錄鏈接指向一個新的控制器,詢問用戶的憑據和驗證他。 我們使用SimpleAuthenticator并在配置文件中配置了用戶名和密碼,因為這是一個非常簡單的方法,我們目前不需要更多的用戶。 我們還確保了所有必需的操作和表單,以便只有已登錄的用戶可以添加新帖子或編輯現有帖子。
- Nette簡介
- 快速開始
- 入門
- 主頁
- 顯示文章詳細頁
- 文章評論
- 創建和編輯帖子
- 權限驗證
- 程序員指南
- MVC應用程序和控制器
- URL路由
- Tracy - PHP調試器
- 調試器擴展
- 增強PHP語言
- HTTP請求和響應
- 數據庫
- 數據庫:ActiveRow
- 數據庫和表
- Sessions
- 用戶授權和權限
- 配置
- 依賴注入
- 獲取依賴關系
- DI容器擴展
- 組件
- 字符串處理
- 數組處理
- HTML元素
- 使用URL
- 表單
- 驗證器
- 模板
- AJAX & Snippets
- 發送電子郵件
- 圖像操作
- 緩存
- 本土化
- Nette Tester - 單元測試
- 與Travis CI的持續集成
- 分頁
- 自動加載
- 文件搜索:Finder
- 原子操作