Vue 3 yönlendirme korumalarıyla rol tabanlı erişim: pratik kalıplar
Vue 3 yönlendirme korumalarını rol tabanlı erişim için pratik örneklerle açıklayan rehber: route meta kuralları, güvenli yeniden yönlendirmeler, kullanıcı dostu 401/403 sayfaları ve veri sızıntılarını önleme.

Route korumaları neyi çözer (ve neyi çözmez)
Route korumaları tek bir işi iyi yapar: navigasyonu kontrol etmek. Bir kullanıcının bir rotaya girip giremeyeceğine ve eğer giremiyorsa nereye gönderileceğine karar verirler. Bu UX'i iyileştirir, ama güvenlikle aynı şey değildir.
Bir menü öğesini gizlemek yalnızca bir ipucudur, yetkilendirme değildir. İnsanlar hala bir URL yazabilir, derin bir bağlantıda sayfayı yenileyebilir veya bir yer imi açabilir. Tek korumanız "buton görünmüyor" ise aslında hiç korumanız yok demektir.
Korumalar, uygulamanın davranışını tutarlı tutmak ve gösterilmemesi gereken sayfaları (ör. admin alanları, dahili araçlar veya rol tabanlı müşteri portalları) engellemek istediğinizde parlıyor.
Korumalar size şunlarda yardımcı olur:
- Sayfaları render olmadan önce engellemek
- Girişe veya güvenli bir varsayılan yere yönlendirmek
- Bozuk bir görünüm yerine temiz bir 401/403 ekranı göstermek
- Kazara oluşan navigasyon döngülerini önlemek
Korumalar tek başına veriyi koruyamaz. Bir API tarayıcıya hassas veri döndürüyorsa, kullanıcı sayfa engellense bile o endpoint'i doğrudan çağırabilir (veya geliştirici araçlarında yanıtları inceleyebilir). Gerçek yetkilendirme sunucu tarafında da yapılmalıdır.
İyi bir hedef her iki tarafı da kapsamaktır: sayfaları engellemek ve veriyi engellemek. Bir destek temsilcisi admin-özel bir rotayı açarsa, koruma navigasyonu durdurup “Erişim reddedildi” göstermeli. Ayrı olarak, backend admin-özel API çağrılarını reddetmeli, böylece kısıtlı veri asla dönmez.
Basit bir rol ve izin modeli seçin
Erişim kontrolü, uzun bir rol listesiyle başladığınızda karmaşıklaşır. Gerçekten insanların anladığı küçük bir setle başlayın, sonra yalnızca ihtiyaç doğduğunda daha ince izinler ekleyin.
Pratik bir ayrım:
- Roller, birinin uygulamadaki kimliğini tanımlar.
- İzinler, ne yapabileceklerini tanımlar.
Çoğu dahili araç için üç rol çok şey karşılar:
- admin: kullanıcıları ve ayarları yönetir, tüm verileri görür
- support: müşteri kayıtlarıyla ilgilenir ve yanıt verir, ancak sistem ayarlarını göremez
- viewer: onaylı ekranlara yalnızca okuma erişimi
Rollerin nereden geldiğine erkenden karar verin. Token claim'leri (JWT) guard'lar için hızlıdır ama yenilenene kadar eskimiş olabilir. Uygulama başında kullanıcı profilini fetch etmek her zaman günceldir, ancak guard'lar bu isteğin bitmesini beklemelidir.
Ayrıca rota türlerinizi açıkça ayırın: genel rotalar (herkese açık), kimlikli rotalar (oturum gerektirir) ve kısıtlı rotalar (rol veya izin gerektirir).
Erişim kurallarını route meta ile tanımlayın
Erişimi ifade etmenin en temiz yolu onu doğrudan rotaya bildirmektir. Vue Router her rota kaydına bir meta nesnesi eklemenize izin verir, böylece guard'lar daha sonra bunu okuyabilir. Bu, kuralları korudukları sayfalara yakın tutar.
Basit bir meta yapısı seçin ve uygulama genelinde ona sadık kalın.
const routes = [
{
path: "/admin",
component: () => import("@/pages/AdminLayout.vue"),
meta: { requiresAuth: true, roles: ["admin"] },
children: [
{
path: "users",
component: () => import("@/pages/AdminUsers.vue"),
// inherits requiresAuth + roles from parent
},
{
path: "audit",
component: () => import("@/pages/AdminAudit.vue"),
meta: { permissions: ["audit:read"] },
},
],
},
{
path: "/tickets",
component: () => import("@/pages/Tickets.vue"),
meta: { requiresAuth: true, permissions: ["tickets:read"], readOnly: true },
},
]
İç içe rotalar için kuralların nasıl birleşeceğine karar verin. Çoğu uygulamada çocuklar ebeveyn gereksinimlerini miras almalıdır. Guard'ınızda yalnızca to.meta değil, eşleşen tüm rota kayıtlarını kontrol edin, böylece ebeveyn kuralları atlanmasın.
İleride zaman kazandıracak bir ayrıntı: "görebilir" ile "düzenleyebilir" arasındaki farkı ayırın. Bir rota support ve admin için görünür olabilir, ama düzenlemeler support için devre dışı bırakılmalıdır. meta içine konan bir readOnly: true bayrağı UI davranışını (aksiyonları devre dışı bırakma, yıkıcı butonları gizleme) yönlendirebilir; bu, güvenlikmiş gibi davranmaktan kaçınır.
Guard'ların güvenilir davranması için auth durumunu hazırlayın
Guard hatalarının çoğu tek bir sorundan kaynaklanır: guard uygulama kullanıcının kim olduğunu bilmeden çalışır.
Auth'ı küçük bir durum makinesi gibi ele alın ve onu tek gerçek kaynak yapın. Üç net durum isteyeceksiniz:
- unknown: uygulama yeni başladı, oturum henüz kontrol edilmedi
- logged out: oturum kontrolü bitti, geçerli kullanıcı yok
- logged in: kullanıcı yüklendi, roller/izinler mevcut
Kural: auth unknown iken rolleri asla okumayın. İşte korunan ekranların yanıp sönmesi veya beklenmedik giriş yönlendirmeleri bundan kaynaklanır.
Oturum yenileme nasıl çalışmalı karar verin
Bir yenileme stratejisi seçin ve bunun öngörülebilir olmasını sağlayın (örneğin: bir token oku, "who am I" endpoint'ine çağrı yap, kullanıcıyı ayarla).
Kararlı bir desen şöyle görünür:
- Uygulama yüklenince auth'ı unknown yapın ve tek bir yenileme isteği başlatın
- Guard'ların yenileme bitene (veya zaman aşımına) kadar beklemesini sağlayın
- Kullanıcıyı bellekte cacheleyin, rota meta içinde saklamayın
- Hata durumunda auth'ı logged out yapın
- Guard'ların bekleyebileceği bir
readypromise'i (veya benzeri) sunun
Bunu yaptıktan sonra guard mantığı basit kalır: auth hazır olana kadar bekle, sonra erişime karar ver.
Adım adım: rota seviyesinde yetkilendirme uygulama
Temiz bir yaklaşım: çoğu kuralı tek bir global guard içinde tutun ve bir rota gerçekten özel mantık gerektirdiğinde per-route guard'ları kullanın.
1) Global bir beforeEach guard ekleyin
// router/index.js
router.beforeEach(async (to) => {
const auth = useAuthStore()
// Step 2: wait for auth initialization when needed
if (!auth.ready) await auth.init()
// Step 3: check authentication, then roles/permissions
if (to.meta.requiresAuth && !auth.isAuthenticated) {
return { name: 'login', query: { redirect: to.fullPath } }
}
const roles = to.meta.roles
if (roles && roles.length > 0 && !roles.includes(auth.userRole)) {
return { name: 'forbidden' } // 403
}
// Step 4: allow navigation
return true
})
Bu, bileşenler arasında kontroller dağıtmadan çoğu durumu kapsar.
beforeEnter ne zaman daha uygundur
Kural gerçekten rota-özgü olduğunda beforeEnter kullanın; örneğin "sadece bilet sahibi bu sayfayı açabilir" gibi ve bu kural to.params.id'ye bağlıysa. Kısa tutun ve aynı auth store'unu yeniden kullanın ki davranış tutarlı olsun.
Delik açmadan güvenli yeniden yönlendirmeler
Yeniden yönlendirmeler güvenliymiş gibi davranırsanız erişim kontrolünüzü sessizce delerek açıklar oluşturabilir.
Yaygın desen: kullanıcı oturum kapalıysa onları girişe gönder ve returnTo sorgu parametresini ekle. Girişten sonra bunu okuyup oraya git. Risk, açık yönlendirmeler (kullanıcıyı istenmeyen bir yere göndermek) ve döngülerdir.
Davranışı basit tutun:
- Oturum kapalı kullanıcıları
Login'e,returnTomevcut yol olarak gönderin. - Oturum açık ama yetkisiz kullanıcıları özel bir
Forbiddensayfasına gönderin (Login değil). - Kabul ettiğiniz
returnTodeğerlerini sınırlayın. - Asla aynı yere yeniden yönlendirmeyecek bir döngü kontrolü ekleyin.
const allowedReturnTo = (to) => {
if (!to || typeof to !== 'string') return null
if (!to.startsWith('/')) return null
// optional: only allow known prefixes
if (!['/app', '/admin', '/tickets'].some(p => to.startsWith(p))) return null
return to
}
router.beforeEach((to) => {
if (!auth.isReady) return false
if (!auth.isLoggedIn && to.name !== 'Login') {
return { name: 'Login', query: { returnTo: to.fullPath } }
}
if (auth.isLoggedIn && !canAccess(to, auth.user) && to.name !== 'Forbidden') {
return { name: 'Forbidden' }
}
})
Navigasyon sırasında kısıtlı verilerin sızmasını önleyin
En kolay sızıntı, kullanıcı yetkili olup olmadığını bilmeden önce veriyi yüklemektir.
Vue'de bu genellikle bir sayfanın setup() içinde veri getirmesi ve router guard'ın daha sonra çalışması şeklinde olur. Kullanıcı yönlendirildiğinde bile yanıt paylaşılan bir store'a düşebilir veya ekranda kısa süreliğine gözükebilir.
Daha güvenli bir kural: önce yetkilendir, sonra yükle.
// router guard: authorize before entering the route
router.beforeEach(async (to) => {
await auth.ready() // ensure roles are known
const required = to.meta.requiredRole
if (required && !auth.hasRole(required)) {
return { name: 'forbidden' }
}
})
Ayrıca hızlı navigasyon değişikliklerinde gelen geç istekler için dikkatli olun. İstekleri AbortController ile iptal edin veya bir istek id'si kontrolüyle geç gelen yanıtları yok sayın.
Önbellekleme başka bir yaygın tuzaktır. "Son yüklenen müşteri kaydı" gibi verileri globalde saklarsanız, admin-özel bir yanıt daha sonra non-admin bir kullanıcıya gösterilebilir. Önbellekleri kullanıcı id'si ve role göre anahtarlayın ve çıkışta (veya roller değiştiğinde) hassas modülleri temizleyin.
Birkaç alışkanlık çoğu sızıntıyı engeller:
- Hassas veriyi yetkilendirme onayı olmadan getirmeyin.
- Önbellekleri kullanıcı ve role göre anahtarlayın veya veriyi sayfa lokalinde tutun.
- Rota değiştiğinde aktif istekleri iptal edin veya geç gelen yanıtları yoksayın.
Dostane yedekler: 401, 403 ve bulunamadı
"Hayır" yolları "evet" yolları kadar önemlidir. İyi yedek sayfalar kullanıcıyı yönlendirir ve destek taleplerini azaltır.
401: Giriş gerekli (kimlik doğrulanmamış)
Kullanıcı oturum açmamışsa 401 kullanın. Mesajı sade tutun: devam etmek için giriş yapmaları gerekiyor. Orijinal sayfaya geri dönüş destekleniyorsa, geri dönüş yolunu doğrulayın ki uygulamanızın dışına yönlendirme olmasın.
403: Erişim reddedildi (kimlik doğrulanmış ama yetkisiz)
Kullanıcı giriş yapmış ama izinleri yoksa 403 kullanın. Mesajı nötr tutun ve hassas detaylara ipucu vermekten kaçının.
İyi bir 403 sayfası genelde net bir başlığa ("Erişim reddedildi"), bir cümlelik açıklamaya ve güvenli bir sonraki adıma sahiptir (panoya dön, admin ile iletişime geç, eğer destekleniyorsa hesabı değiştir).
404: Bulunamadı
404'ü 401/403'ten ayrı yönetin. Aksi halde insanlar sayfanın olmadığı durumlarda yetki eksikliği olduğunu zannedebilir.
Erişim kontrolünü bozan yaygın hatalar
Çoğu hata basit mantık kaymalarıdır: yönlendirme döngüleri, yanlış sayfanın kısa süreli gösterilmesi veya kullanıcıların takılı kalması.
Sık görülen sebepler:
- Gizli UI'yi "güvenlik" sanmak. Router ve API'de rolleri her zaman zorlayın.
- Çıkış/giriş sonrası eski durumdan roller okumak.
- Yetkisiz kullanıcıları başka korumalı bir rotaya yönlendirmek (anında döngü).
- Yeniden yüklemede "auth hala yükleniyor" anını göz ardı etmek.
- 401 ile 403'ü karıştırmak, kullanıcıları şaşırtır.
Gerçekçi bir örnek: bir destek temsilcisi çıkış yapar ve aynı paylaşılan bilgisayarda bir admin giriş yapar. Eğer guard yeni oturum doğrulanana kadar önbelleğe alınmış bir rolü okursa, admin yanlışlıkla engellenebilir veya daha kötüsü kısa süreliğine erişime izin verilebilir.
Yayına almadan önce hızlı kontrol listesi
Erişim kontrolünün genellikle kırıldığı anlara odaklanan kısa bir kontrol geçin: yavaş ağlar, süresi dolmuş oturumlar ve yer imli URL'ler.
- Her korunan rota açık
metagereksinimlerine sahip. - Guard'lar auth-yüklenme durumunu UI'nin korunaksız şekilde yanıp sönmesini önleyecek şekilde ele alır.
- Yetkisiz kullanıcılar net bir 403 sayfasına (karışık bir ana sayfaya zıplama değil) yönlendirilir.
- Herhangi bir "geri dön" yönlendirmesi doğrulanmış ve döngü oluşturmayacak şekilde sınırlandırılmış.
- Hassas API çağrıları yalnızca yetkilendirme onayı sonrası çalışır.
Sonra bir senaryoyu baştan sona test edin: korunan bir URL'yi yeni bir sekmede, oturum açmamışken açın; temel kullanıcı olarak giriş yapın ve izinliyse hedef sayfaya gelip gelmediğinizi veya izinli değilse temiz bir 403 ile bir sonraki adımı görebildiğinizi doğrulayın.
Örnek: küçük bir web uygulamasında support vs admin erişimi
Bir helpdesk uygulaması hayal edin: iki rol var — support ve admin. Support ticket'ları okuyup cevaplayabilir. Admin bunları yapabilir ve ayrıca faturalandırma ile şirket ayarlarını yönetir.
/tickets/:idhemsupporthemadminiçin izinlidir/settings/billingyalnızcaadminiçindir
Şimdi yaygın bir durum: support temsilcisi eski bir yer iminden /settings/billing derin linkini açar. Guard rota meta'sını sayfa yüklenmeden önce kontrol etmeli ve navigasyonu engellemelidir. Kullanıcı oturum açmış ama rolü yetersiz olduğu için güvenli bir yedek (403) sayfasına düşmelidir.
İki mesaj önemlidir:
- Giriş gerekli (401): “Devam etmek için lütfen giriş yapın.”
- Erişim reddedildi (403): “Faturalandırma Ayarlarına erişiminiz yok.”
Olmaması gereken: faturalandırma bileşeninin mount edilmesi veya faturalandırma verilerinin, kısa da olsa, getirilmesi.
Roller oturum süresi içinde değişirse ek kenar durumları oluşur. Birini terfi ettiniz veya rolünü düşürdünüzse menüye güvenmeyin. Navigasyonda rollerini yeniden kontrol edin ve profil değiştiğinde auth durumunu yenileyin veya rol değişimini algılayıp artık izin verilmeyen sayfalardan yönlendirme yapın.
Sonraki adımlar: erişim kurallarını sürdürülebilir kılın
Guard'lar çalıştıktan sonra daha büyük risk sürüklenmedir: yeni bir rota meta'sız yayınlanır, bir rol yeniden adlandırılır ve kurallar tutarsızlaşır.
Kurallarınızı küçük bir test planına dönüştürün ve yeni rota eklediğinizde çalıştırın:
- Misafir olarak: korunan rotaları açın ve kısmi içerik görmeden giriş sayfasına yönlendirildiğinizi doğrulayın.
- Kullanıcı olarak: erişmemesi gereken bir sayfayı açın ve net bir 403 aldığınızı doğrulayın.
- Admin olarak: adres çubuğundan kopyalanmış derin bağlantıları deneyin.
- Her rol için: korunan bir rotada yenileme yapın ve sonucu kararlı olduğunu doğrulayın.
Ek bir güvenlik ağı isterseniz, eksik kuralların hemen fark edilmesi için rota ve meta gereksinimlerini listeleyen geliştirici-özel bir görünüm veya konsol çıktısı ekleyin.
Eğer AppMaster (appmaster.io) ile dahili araçlar veya portallar inşa ediyorsanız, aynı yaklaşımı uygulayın: Vue3 UI içindeki route guard'larını navigasyona odaklandırın ve izinleri backend mantığı ve verinin yaşadığı yerde zorlayın.
Bir iyileştirme seçin ve uçtan uca uygulayın: veri-getirme kapılarını sıkılaştırın, 403 sayfasını iyileştirin veya yeniden yönlendirme işlemlerini kilitleyin. Küçük düzeltmeler gerçek dünyadaki çoğu erişim hatasını durdurur.
SSS
Route korumaları navigasyonu kontrol eder, veri erişimini kendiliğinden sağlamaz. Bir sayfayı engellemenize, yönlendirmenize ve temiz bir 401/403 durumu göstermenize yardımcı olurlar, fakat bir kullanıcı API'nizi doğrudan çağırmayı engelleyemez. Kısıtlı verilerin hiçbir zaman dönmemesi için aynı izinleri sunucu tarafında da uygulayın.
Menü öğesini gizlemek, birinin gördüğünü değiştirir fakat istekte bulunmasını engellemez. Kullanıcılar hâlâ URL yazabilir, yer imi açabilir veya derin bağlantıya gidebilir. Sayfayı engellemek için router kontrolüne, veriyi engellemek için sunucu tarafı yetkilendirmesine ihtiyacınız var.
İlk olarak insanların gerçekten anlayacağı küçük bir setle başlayın, sonra gerçek ihtiyaç doğduğunda izinler ekleyin. Yaygın bir temel: admin, support ve viewer. Ardından tickets:read veya audit:read gibi özel eylemler için izinler ekleyin. "Kim olduğunu" (role) ile "ne yapabileceğini" (permission) ayrı tutun.
Erişim kurallarını rota kayıtlarının meta alanına koyun: örneğin requiresAuth, roles ve permissions. Bu kurallar sayfaların hemen yanında olur ve global guard'ınızın tahmin edilebilir kalmasını sağlar. İç içe geçmiş rotalar için, ebeveyn gereksinimlerinin atlanmaması adına her eşleşen kayıt üzerinde kontrol edin.
to.matched içinden okuyup tüm eşleşen rota kayıtları boyunca gereksinimleri birleştirin. Böylece bir çocuk rota, ebeveynin requiresAuth veya roles gereksinimini atlayamaz. Baştan açık bir birleştirme kuralı belirleyin (çoğunlukla: ebeveyn gereksinimleri çocuklara uygulanır).
Guard uygulama kullanıcının kim olduğunu bilmeden önce çalıştığında bu tür sorunlar çıkar. Kimlik doğrulamayı üç durum olarak ele alın — unknown, logged out, logged in — ve auth unknown iken rollerin değerlendirilmesine asla izin vermeyin. Guard'ların bir başlatma adımının (ör. tek bir "who am I" isteği) bitmesini beklemesini sağlayın.
Genel kurallar için varsayılan olarak global beforeEach kullanın (ör. "giriş gerektirir" veya "rol/izin gerektirir"). beforeEnter yalnızca kural gerçekten rota-özgü ve paramsa bağlıysa (ör. "yalnızca bilet sahibi bu sayfayı açabilir") kullanılmalı. Her iki yol da aynı kimlik kaynağını kullanmalı.
returnTo güvensiz girdidir. Sadece dahili yolları kabul edin (ör. / ile başlayan ve bilinen öneklerle eşleşen değerler) ve yönlendirmelerin aynı engellenmiş rotaya tekrar dönmesini önleyecek basit bir döngü kontrolü ekleyin. Oturumu kapatmış kullanıcılar Login sayfasına, oturum açık ama yetkisiz olanlar 403 sayfasına gitmeli.
Yetkilendirme onaylanmadan veri getirmeyin. Bir sayfa setup() içinde veri alıyorsa ve kısa süre sonra yönlendirilirse, yanıt hala store'a düşebilir veya kısa süreliğine gösterilebilir. Duyarlı istekleri onaylanmış yetkilendirme arkasına alın, rota değiştiğinde işlemleri iptal edin veya geç gelen yanıtları yoksayın.
401: Kullanıcı giriş yapmamışsa kullanın. 403: Kullanıcı giriş yapmış ama yetkili değilse kullanın. 404: Bulunamadı durumu, 401/403'ten ayrı ele alınmalı; aksi halde kullanıcılar bir sayfanın gerçekten mevcut olmadığını düşünmek yerine yetki eksikliği olduğunu varsayar. Tutarlı ve net geri dönüşler kafa karışıklığını azaltır.


