Herkese Merhabalar arkadaşlar! Bugün Angular 2 ve üzeri versiyonlarda JWT token kullanarak giriş işlemini ve sonrasında başlatılan oturumun (session) nasıl devam ettirileceğini konuşacağız. Oturum yönetimi ilk bakışta korkutucu gelebilir, hele bir de “token nereye gidecek, her isteğe nasıl ekleyeceğim?” derken iş iyice karışık görünebilir. Ama merak etmeyin; Angular, JWT token bazlı oturum yönetiminde çalışması en rahat frameworklerden biri ve gelişmiş mimarisi sayesinde bu işi şaşırtıcı derecede temiz bir şekilde halledebiliyoruz.
Önce “neden” sorusuna bir cevap verelim, çünkü ne yaptığımızı anlamadan kod yazmak pek hoşuma gitmiyor. Klasik MVC yapılarda kimlik bilgisini genellikle cookie üzerinde taşırız ve server her istekte bu cookie’yi otomatik okur. Ancak SPA (Single Page Application) uygulamalarında işler biraz farklı işliyor; burada cookie yerine JWT token ve benzeri token yapıları tercih ediliyor.
Sebebi aslında basit: SPA uygulamalarında client tarafından gönderilen HTTP isteklerinin server tarafında doğrulanabilmesi için Authorization header’ı kullanılıyor. Giriş işlemi sırasında kullanıcıya bir erişim tokeni (Access Token) veriliyor ve sonraki her istekte bu token ile kimlik doğrulaması yapılıyor. JWT’nin kendisinin ne olduğunu, içinde neler taşıdığını merak ediyorsanız RFC 7519 (JWT spesifikasyonu) ve jwt.io introduction sayfaları gayet güzel anlatıyor.
İlk adımımız net: giriş işlemini yaptıktan sonra API’nin bize döndüğü erişim tokenini bir yere kaydetmemiz gerekiyor ki sonraki isteklerde tekrar tekrar kullanabilelim. Bunun için en pratik yer tarayıcının Local Storage alanı.
// auth.service.ts
login(credentials: LoginRequest) {
return this.http.post<LoginResponse>('/api/auth/login', credentials).pipe(
tap((res) => localStorage.setItem('access_token', res.accessToken))
);
}
Burada minik bir uyarı yapayım: Local Storage pratik olsa da XSS saldırılarına karşı tamamen korunaklı değil, dolayısıyla yüksek güvenlik gerektiren senaryolarda HttpOnly cookie gibi alternatifleri de değerlendirmek gerekebilir. Ama bu yazının amacı doğrultusunda Local Storage gayet iş görüyor.
Tokeni kaydettik, peki şimdi onu gönderdiğimiz her HTTP isteğine nasıl ekleyeceğiz? Aklınıza ilk gelen şey “her servis çağrısında header’ı tek tek elle eklerim” olabilir, ama inanın bu hem çok zaman alır hem de bir süre sonra bakımı kabusa döner. İşte tam burada Angular ile birlikte gelen Interceptor yapısı devreye giriyor.
Eğer backend tarafında biraz vakit geçirdiyseniz “middleware” kavramına yabancı değilsinizdir. Middleware yapıları sayesinde backend’de gerçekleşen iki yönlü trafiği (request ve response) tek bir merkezden kontrol eder ve manipüle ederiz. Interceptor’ler de aslında tam olarak bu middleware mantığıyla çalışıyor diyebiliriz. Angular üzerinde HttpClient ile gönderdiğimiz istekleri interceptor yardımıyla dinleyebilir, kontrol edebilir ve manipüle edebiliriz; hem de bütün isteklere tek tek müdahale etmeden, sadece tek bir tanımlama ile merkezi bir şekilde.
Yukarıda bahsettiğimiz gibi interceptor ile request ve response üzerinde rahatça işlem yapabiliyoruz. Bizim senaryomuzda yapacağımız şey çok basit: login sonrası aldığımız JWT token değerini, giden bütün isteklerin header kısmına tek bir hamle ile eklemek.
Öncelikle interceptor’ümüzü oluşturalım. Aşağıdaki CLI komutunu kullanabileceğiniz gibi dosyayı manuel de oluşturabilirsiniz; tek yapmanız gereken oluşturduğunuz sınıfa HttpInterceptor arayüzünü implement etmek.
ng generate interceptor append-jwt-token Sonrasında oluşan dosyayı açıp Local Storage’daki tokeni okuyarak isteğin header bilgilerine Authorization alanını ekliyoruz. Angular’ın son versiyonlarıyla birlikte artık standalone, fonksiyonel interceptor’ler kullanmanızı öneririm; çünkü hem daha az boilerplate üretiyorlar hem de yeni mimari ile çok daha uyumlular:
// append-jwt-token.interceptor.ts
import { HttpInterceptorFn } from '@angular/common/http';
export const appendJwtTokenInterceptor: HttpInterceptorFn = (req, next) => {
const token = localStorage.getItem('access_token');
if (token) {
const authReq = req.clone({
setHeaders: { Authorization: `Bearer ${token}` },
});
return next(authReq);
}
return next(req);
};
Burada dikkat ettiyseniz gelen req nesnesini doğrudan değiştirmiyor, clone() ile kopyasını alıp onu manipüle ediyoruz. Bunun sebebi HttpRequest nesnelerinin immutable olması; yani üzerinde doğrudan değişiklik yapamıyoruz, malesef bir kopya almak zorundayız. Bu aslında güzel bir şey, çünkü isteklerin yan etkisiz kalmasını garantiliyor.
Son adım olarak bu interceptor’ü uygulamamıza tanıtmamız gerekiyor. Standalone bir Angular uygulamasında bunu app.config.ts içerisinde provideHttpClient ile şöyle bağlıyoruz:
// app.config.ts
import { ApplicationConfig } from '@angular/core';
import { provideHttpClient, withInterceptors } from '@angular/common/http';
import { appendJwtTokenInterceptor } from './append-jwt-token.interceptor';
export const appConfig: ApplicationConfig = {
providers: [
provideHttpClient(withInterceptors([appendJwtTokenInterceptor])),
],
};
Hâlâ klasik NgModule tabanlı bir projede çalışıyorsanız endişeye gerek yok; class tabanlı bir interceptor yazıp app.module.ts içerisindeki providers bölümünde HTTP_INTERCEPTORS token’ı ile (ve multi: true diyerek) tanımlamanız yeterli. İki yaklaşım da aynı işi yapıyor; konunun resmi detayları için Angular HTTP Interceptors dokümantasyonuna göz atabilirsiniz.
İşte bu kadar! Artık HttpClient üzerinden gönderdiğiniz bütün istekler bu interceptor’e uğrayacak, header bilgileri yeniden düzenlenecek ve token otomatik olarak eklenerek gönderilecek. Tek bir tanımlama, tüm istekler için geçerli.
Gördüğünüz üzere Angular’da interceptor’ler ve JWT token ile oturum yönetimi gerçekten oldukça kolay arkadaşlar. Burada ağırlıklı olarak tokeni nasıl handle edeceğimizi gösterdik; ancak token süresi dolduğunda yapılacak refresh token akışı, 401 hatalarını yakalayıp kullanıcıyı login sayfasına yönlendirme gibi konular da var ve bunlara bir diğer yazımızda ayrıntılı gireceğiz. O zamana kadar Angular ekosistemini biraz daha tanımak isterseniz Angular NGXS ile state management, Routing ve Lazy Loading ve Dependency Injection yazılarıma da göz atabilirsiniz. Merak ettiğiniz başka hususlar olursa sormaktan çekinmeyin 🙂
Angular Signals nedir, Zone.js tabanlı change detection'ın neden yerini alıyor ve signal(), computed(), effect() kavramlarını…
Building AI applications without a clear context management system is like coding without version control.…
In the world of AI and Large Language Models (LLMs), one thing has become very…
Herkese Merhabalar. Bildiğiniz üzere bu ay Angular 17 yepyeni bir imaj çalışması ile birlikte yayına…
Herkese merhaba arkadaşlar. Önceki yazımızda openlayers nedir ve neden kullanmalıyız sorunu yanıtlamıştık. Popüler harita kütüphanelerinden…
Merhaba arkadaşlar. Eğer CBS (Coğrafi Bilgi Sistemleri) dünyasına yeni yeni adımlar atıyorsanız adını sık sık…