#[Requires] Attribute'u Nasıl Kullanılır

Bir web uygulaması yazarken, uygulamanızın belirli bölümlerine erişimi kısıtlama ihtiyacıyla sık karşılaşırsınız. Belki bazı isteklerin yalnızca bir form üzerinden veri gönderebilmesini (yani POST metodunu kullanmasını) ya da yalnızca AJAX çağrılarına açık olmasını istersiniz. Nette Framework 3.2'de, bu tür kısıtlamaları şık ve anlaşılır biçimde koymanızı sağlayan yeni bir araç geldi: #[Requires] attribute'u.

Attribute, PHP'de bir sınıf ya da metot tanımından önce eklediğiniz özel bir işarettir. Özünde bir sınıf olduğundan, aşağıdaki örneklerin çalışması için use deyimini eklemeniz gerekir:

use Nette\Application\Attributes\Requires;

#[Requires] attribute'unu presenter sınıfının kendisinde ve şu metotlarda kullanabilirsiniz:

  • action<Action>()
  • render<View>()
  • handle<Signal>()
  • createComponent<Name>()

Son iki metot bileşenler için de geçerlidir, dolayısıyla attribute'u onlarla da kullanabilirsiniz.

Attribute'un belirttiği koşullar sağlanmazsa bir HTTP 4xx hatası tetiklenir.

HTTP Metotları

Erişim için hangi HTTP metotlarına (GET, POST vb.) izin verildiğini belirtebilirsiniz. Örneğin erişime yalnızca bir form gönderilerek izin vermek istiyorsanız şunu ayarlayın:

class AdminPresenter extends Nette\Application\UI\Presenter
{
	#[Requires(methods: 'POST')]
	public function actionDelete(int $id): void
	{
	}
}

Durum değiştiren eylemlerde neden GET yerine POST kullanmalısınız ve bunu nasıl yaparsınız? Kılavuzu okuyun.

Bir metot ya da metot dizisi belirtebilirsiniz. Özel bir durum, tüm metotlara izin veren '*' değeridir; presenter'lar bunu güvenlik nedeniyle varsayılan olarak yapmaz.

AJAX Çağrıları

Bir presenter'ın ya da metodun yalnızca AJAX istekleriyle erişilebilir olmasını istiyorsanız şunu kullanın:

#[Requires(ajax: true)]
class AjaxPresenter extends Nette\Application\UI\Presenter
{
}

Aynı Kaynak

Güvenliği artırmak için isteğin aynı alan adından yapılmasını zorunlu kılabilirsiniz. Bu, CSRF açığını önler:

#[Requires(sameOrigin: true)]
class SecurePresenter extends Nette\Application\UI\Presenter
{
}

handle<Signal>() metotlarında aynı alan adından erişim otomatik olarak zorunludur. Bu yüzden herhangi bir alan adından erişime izin vermek istiyorsanız şunu belirtin:

#[Requires(sameOrigin: false)]
public function handleList(): void
{
}

Forward ile Erişim

Bazen bir presenter'a erişimi, yalnızca dolaylı olarak, örneğin başka bir presenter'dan forward() ya da switch() metotlarıyla ulaşılabilecek şekilde kısıtlamak yararlıdır. Örneğin hata presenter'ları, URL'den tetiklenmelerini önlemek için böyle korunur:

#[Requires(forward: true)]
class ForwardedPresenter extends Nette\Application\UI\Presenter
{
}

Pratikte, yalnızca presenter'daki mantığa göre erişilebilecek belirli view'ları işaretlemek çoğu zaman gerekir. Yine, doğrudan açılamamaları için:

class ProductPresenter extends Nette\Application\UI\Presenter
{

	public function actionDefault(int $id): void
	{
		$product = $this->facade->getProduct($id);
		if (!$product) {
			$this->setView('notfound');
		}
	}

	#[Requires(forward: true)]
	public function renderNotFound(): void
	{
	}
}

Belirli Eylemler

Bileşen oluşturmak gibi belirli bir kodun yalnızca presenter'daki belirli eylemlerde erişilebilir olmasını da kısıtlayabilirsiniz:

class EditDeletePresenter extends Nette\Application\UI\Presenter
{
	#[Requires(actions: ['add', 'edit'])]
	public function createComponentPostForm()
	{
	}
}

Tek bir eylem söz konusuysa dizi yazmaya gerek yoktur: #[Requires(actions: 'default')]

Özel Attribute'lar

#[Requires] attribute'unu aynı ayarlarla defalarca kullanmak istiyorsanız, #[Requires] attribute'undan türeyen ve onu ihtiyacınıza göre yapılandıran kendi attribute'unuzu oluşturabilirsiniz.

Örneğin #[SingleAction], erişime yalnızca default eylemi üzerinden izin verir:

#[\Attribute]
class SingleAction extends Nette\Application\Attributes\Requires
{
	public function __construct()
	{
		parent::__construct(actions: 'default');
	}
}

#[SingleAction]
class SingleActionPresenter extends Nette\Application\UI\Presenter
{
}

Ya da #[RestMethods], REST API'de kullanılan tüm HTTP metotlarıyla erişime izin verir:

#[\Attribute]
class RestMethods extends Nette\Application\Attributes\Requires
{
	public function __construct()
	{
		parent::__construct(methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE']);
	}
}

#[RestMethods]
class ApiPresenter extends Nette\Application\UI\Presenter
{
}

Sonuç

#[Requires] attribute'u, web sayfalarınıza nasıl erişildiği konusunda size büyük esneklik ve denetim verir. Basit ama güçlü kurallarla uygulamanızın güvenliğini ve düzgün çalışmasını artırabilirsiniz. Gördüğünüz gibi, Nette'de attribute kullanmak işinizi yalnızca kolaylaştırmakla kalmaz, aynı zamanda güvenli hâle getirir.