Betmen35 Önce temel kavramları öğrenelim:
Authentication - Kimlik doğrulaması
Sisteminizdeki kullanıcıların "login" dediğimiz yol ile sisteme giriş yapmasını ifade eder. "credentials" şeklinde ifade edilen kullanıcı adı ve şifre gibi bilgiler kullanılarak kullanıcı bulunur ve bilgileri istekler arasında tutulur ve gerektiğinde kullanılır.
Authorization - Yetkilendirme
Giriş yapmış kullanıcıya rol ve yetki gibi bazı özellikler vererek sistem içerisinde kullanıcının davranışını kontrol altında tutmayı ifade eder. Size verdiğim link Laravel içinde yer alan yetkilendirme ile ilgili bölüm.
Gate ve Policy kavramlarının Spatie'nin permission paketinde geçmesinin sebebi paketin bunlarla birlikte ve uyumlu çalışması.
Laravel'de yetkinlendirme için kullanılan iki tane yöntem var. Biri Gate diğeri ise Policy. Gate kullanıcının herhangi bir işlemi yapmasını kontrol eden genel işlemlerde kullanılırken Policy ise bir kaynak üzerindeki (mesela bir Eloquent Modeli) işlemlerini kontrol etmek için kullanılır. Yani Gate genel, Policy ise özel kontrol sağlar. Örnek vermek gerekirse, bir kullanıcının uygulama içindeki bir sayfaya erişmesini istemiyorsanız Gate kullanabilirsiniz ama bir kullanıcının sisteme bir yazı eklemesini kontrol etmek isterseniz; ekleyebilsin, sadece kendi yazılarını silebilsin ve düzenleyebilsin derseniz burada Policy daha uygun olacaktır.
Gate
Gate tanımlamarı AppServiceProvider::boot() içine yazılır. Örneğin
public function boot(): void
{
// send-mail isimli bir Gate. Giriş yapmış kullanıcı içeriye $user adıyla
// otomatik olarak enjekte edilir.
Gate::define('send-mail', function (User $user) {
// Spatie paketiyle birlikte kullanılabilir.
// Yöntem true ya da false dönmelidir.
return $user->hasPermissionTo('mail');
// ya da return $user->email === 'my@domain.com'; gibi.
});
// Eğer verilen Post modeli kullanıcı tarafından oluşturulmuş ise
// güncellemesine izin ver.
Gate::define('update-post', function (User $user, Post $post) {
return $user->id === $post->user_id;
});
}
Kullanımı ise, mesela bir controller yöntemi içinde:
if (!Gate::allows('send-mail')) {
// Kullanıcının mail gönderme yetkisi yok!
}
// Mail gönder...
$post = Post::findOrFail($id);
if (!Gate::allows('update-post', $post)) {
// Kullanıcının bu Post modelini düzenleme yetkisi yok.
}
// $post->update($data)
Policy
Policy Gate aksine bir organizasyon gerektirdiği için bir sınıf içerisinde tanımlanır. Genelde app/Policies isiml ibr klasöre konur ve isimleri de genellikle {ModelAdi}Policy şeklinde olur. Mesela app/Policies/PostPolicy.php gibi. Aşağıda bir tane Post modeli ile kullanılabilecek bir PostPolicy örneği verdim. Ben elle yazdım ama siz php artisan make:policy PostPolicy
kullanarak otomatik olarak da oluşturabilirsiniz. Yöntem parametresi olarak User $user kullandığınızda Laravel otomatik olarak giriş yapmış kullanıcıyı Gate'de olduğu gibi enjekte eder:
namespace App\Policies;
use App\Models\Post;
use App\Models\User;
class PostPolicy
{
// Kullanıcı posts.list yetkisine sahip ise yazıları listeleyebilsin
public function list(User $user): bool
{
return $user->hasPermissionTo('posts.list');
}
// Kullanıcı posts.create yetkisine sahip ise yazı ekleyebilsin
public function create(User $user): bool
{
return $user->hasPermissionTo('posts.create');
}
// Kullanıcı posts.edit yetkisine sahip ise sadece kendi yazdığı yazıları düzenleyebilsin
public function update(User $user, Post $post): bool
{
return $user->hasPermissionTo('posts.edit')
&& $user->id === $post->user_id;
}
// Kullanıcı posts.delete yetkisine sahip ise sadece kendi yazdığı yazıları silebilsin.
public function delete(User $user, Post $post): bool
{
return $user->hasPermissionTo('posts.delete')
&& $user->id === $post->user_id;
}
}
Eğer app/Policies/{ModelAdi}Policy.php
kuralına uyarsanız Laravel Policy dosyalarını kendisi otomatik bulur, bir yerde tanımlama yapmanıza gerek kalmaz ama farklı bir kullanım yapıp kendiniz kaydetmek isterseniz yine aynı şekilde AppServiceProvider::boot() içerisinde tanımlamasını yaparsınız:
public function boot(): void
{
// Gate Tanımlamaları
Gate::define('send-mail', function (User $user) {
return $user->hasPermissionTo('mail');
});
Gate::define('update-post', function (User $user, Post $post) {
return $user->id === $post->user_id;
});
// Policy Tanımlamaları
// Post modeli için PostPolicy (app/FarkliBirKlasor/PostPolicy.php) kullan:
Gate::policy(Post::class, PostPolicy::class);
}
Kullanımı ise:
class PostController extends Controller
{
public function index()
{
// PostPolicy::list() yöntemi sadece $user parametresi aldığı için $post yerine
// biz elle Post::class vermeliyiz. Böylece list yöntemi için hangi Policy
// dosyasına bakmasına gerektiğini bulacak. Bunu AppServiceProvider içinde
// Gate::policy(Post::class, PostPolicy::class); şeklinde tanımlamıştık.
if(Auth::user()->cannot('list', Post::class))) {
// Kullanıcının yazıları listeleme yetkisi yok!
}
//...
}
public function update(Request $request, Post $post)
{
// can (yapabilir) ve cannot (yapamaz) şeklinde iki yöntem var. İstediğinizi
// kullanabilirsiniz. Üstte cannot() kullandım, burada can() kullandım örneğin.
// Burada ayrıca Request olduğu için Auth kullanmama gerek yok,
// $request->user() ile kullanıcıya ulaşabilirim.
if (!$request->user()->can('update', $post)) {
// Kullanıcının bu yazıyı güncelleme yetkisi yok!
// abort(403);
}
//...
}
}
Dokümanda konuyla ilgili diğer şeyler anlatılmış ama hepsini burada anlatamam. Benim size tavsiyem Laravel'den önce şu konulara ağırlık vermeniz:
- İngilizce
- Teknik doküman ve kod okurluğu
- Temel ve modern PHP bilgisi