Kimlik Doğrulama

Nette, sitelerimizde kimlik doğrulama programlamanın bir yolunu sunar, ancak bizi hiçbir şeye zorlamaz. Uygulama tamamen bize bağlıdır. Nette, yalnızca kullanıcıyı istediğimiz şekilde doğrulayan tek bir authenticate metodu gerektiren Nette\Security\Authenticator arayüzünü içerir.

Bir kullanıcının doğrulanabileceği birçok olasılık vardır. En yaygın doğrulama yöntemi şifre iledir (kullanıcı adını veya e-postasını ve şifresini sağlar), ancak başka yollar da vardır. Bazı sitelerde “Facebook ile Giriş Yap” veya Google/Twitter/GitHub ile giriş yapma gibi düğmeleri biliyor olabilirsiniz. Nette ile herhangi bir giriş yöntemine sahip olabiliriz veya bunları birleştirebiliriz. Bu tamamen bize bağlıdır.

Normalde kendi kimlik doğrulayıcımızı yazardık, ancak bu basit küçük blog için yapılandırma dosyasında saklanan şifre ve kullanıcı adına göre giriş yapan yerleşik kimlik doğrulayıcıyı kullanacağız. Test amaçları için kullanışlıdır. Bu nedenle, config/common.neon yapılandırma dosyasına aşağıdaki security bölümünü ekleyeceğiz:

security:
	users:
		admin: secret  # kullanıcı 'admin', şifre 'secret'

Nette, DI konteynerinde otomatik olarak bir servis oluşturur.

Giriş Formu

Şimdi kimlik doğrulamamız hazır ve giriş yapmak için kullanıcı arayüzünü hazırlamamız gerekiyor. Bu nedenle, SignPresenter adlı yeni bir presenter oluşturalım:

  • giriş formunu görüntüler (giriş adı ve şifre ile)
  • form gönderildikten sonra kullanıcıyı doğrular
  • oturumu kapatma seçeneği sunar

Giriş formuyla başlayalım. Presenter'larda formların nasıl çalıştığını zaten biliyoruz. Bu nedenle bir SignPresenter presenter'ı oluşturacağız ve createComponentSignInForm metodunu yazacağız. Şöyle görünmelidir:

<?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', 'Kullanıcı adı:')
			->setRequired('Lütfen kullanıcı adınızı girin.');

		$form->addPassword('password', 'Şifre:')
			->setRequired('Lütfen şifrenizi girin.');

		$form->addSubmit('send', 'Giriş yap');

		$form->onSuccess[] = $this->signInFormSucceeded(...);
		return $form;
	}
}

Kullanıcı adı ve şifre için alanlar vardır.

Şablon

Form, in.latte şablonunda işlenecektir:

{block content}
<h1 n:block=title>Giriş Yap</h1>

{control signInForm}

Giriş Callback'i

Ardından, form başarıyla gönderildikten hemen sonra çağrılacak olan kullanıcı girişi için callback'i ekleyeceğiz.

Callback yalnızca kullanıcının doldurduğu kullanıcı adını ve şifreyi alır ve bunları kimlik doğrulayıcıya iletir. Giriş yaptıktan sonra ana sayfaya yönlendiririz.

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('Yanlış kullanıcı adı veya şifre.');
	}
}

User::login() metodu, kullanıcı adı ve şifre yapılandırma dosyasındaki verilerle eşleşmezse bir istisna atar. Zaten bildiğimiz gibi, bu kırmızı bir hata sayfasına veya üretim modunda bir sunucu hatası hakkında bilgi veren bir mesaja neden olabilir. Ancak bunu istemiyoruz. Bu nedenle bu istisnayı yakalarız ve forma güzel, kullanıcı dostu bir hata mesajı iletiriz.

Formda bir hata oluştuğunda, form içeren sayfa yeniden çizilir ve formun üzerinde kullanıcıya yanlış giriş adı veya şifre girdiğini bildiren güzel bir mesaj görüntülenir.

Presenter'ların Güvenliğini Sağlama

Gönderi ekleme ve düzenleme formunu güvence altına alacağız. Bu, EditPresenter presenter'ında tanımlanmıştır. Amaç, oturum açmamış kullanıcıların sayfaya erişimini engellemektir.

Presenter yaşam döngüsünün hemen başında çalışan startup() metodunu oluşturacağız. Bu metot, oturum açmamış kullanıcıları giriş sayfasına yönlendirir.

public function startup(): void
{
	parent::startup();

	if (!$this->getUser()->isLoggedIn()) {
		$this->redirect('Sign:in');
	}
}

Bağlantıları Gizleme

Yetkisiz bir kullanıcı artık create veya edit sayfasını göremez, ancak yine de onlara bağlantıları görebilir. Bunları da gizlemeliyiz. Böyle bir bağlantı app/Presentation/Home/default.latte şablonundadır ve yalnızca oturum açmış kullanıcılar tarafından görülmelidir.

Bunu n:if adlı bir n:attribute kullanarak gizleyebiliriz. Bu koşul false ise, içerik dahil tüm <a> etiketi gizli kalacaktır.

<a n:href="Edit:create" n:if="$user->isLoggedIn()">Gönderi oluştur</a>

bu, aşağıdaki gösterimin kısaltmasıdır (tag-if ile karıştırılmamalıdır):

{if $user->isLoggedIn()}<a n:href="Edit:create">Gönderi oluştur</a>{/if}

Aynı şekilde app/Presentation/Post/show.latte şablonundaki bağlantıyı da gizleyeceğiz.

Giriş Bağlantısı

Aslında giriş sayfasına nasıl ulaşırız? Ona yönlendiren hiçbir bağlantı yok. Öyleyse onu @layout.latte şablonuna ekleyelim. Uygun bir yer bulmaya çalışın – hemen hemen her yerde olabilir.

...
<ul class="navig">
	<li><a n:href="Home:">Makaleler</a></li>
	{if $user->isLoggedIn()}
		<li><a n:href="Sign:out">Çıkış yap</a></li>
	{else}
		<li><a n:href="Sign:in">Giriş yap</a></li>
	{/if}
</ul>
...

Kullanıcı oturum açmamışsa, “Giriş yap” bağlantısı görüntülenir. Aksi takdirde, “Çıkış yap” bağlantısı görüntülenir. Bu eylemi SignPresenter'a da ekleyeceğiz.

Kullanıcıyı oturumu kapattıktan hemen sonra yönlendirdiğimiz için herhangi bir şablona gerek yoktur. Oturumu kapatma şöyle görünür:

public function actionOut(): void
{
	$this->getUser()->logout();
	$this->flashMessage('Başarıyla çıkış yapıldı.');
	$this->redirect('Home:');
}

Yalnızca logout() metodu çağrılır ve ardından başarılı oturum kapatmayı onaylayan güzel bir mesaj görüntülenir.

Özet

Giriş yapmak ve ayrıca kullanıcının oturumunu kapatmak için bir bağlantımız var. Doğrulama için yerleşik kimlik doğrulayıcıyı kullandık ve giriş bilgileri yapılandırma dosyasındadır, çünkü bu basit bir test uygulamasıdır. Ayrıca düzenleme formlarını da güvence altına aldık, böylece yalnızca oturum açmış kullanıcılar gönderi ekleyebilir ve düzenleyebilir.

Burada kullanıcı girişi ve Yetki Doğrulama hakkında daha fazla bilgi edinebilirsiniz.