
Merhabalar,
Bir önceki yazımda Spring’in Mühendislik harikası bir framework olduğundan bahsetmiştim. Dilerseniz o yazımı da okuyabilirsiniz.
Bugün size Spring Framework ile gelen Spring Security Framework’ü hakkında kendimce pek bilinmeyenleri anlatacağım.
Konuya başlamadan önce, öncelikle şunu yineleyerek belirtmek istiyorum. Sektördeki bir çok yazılımcı ya da kendisini yazılımcı olarak niteleyen bir çok insan, ellerindeki yazılım geliştirme araçlarını kullanırken, kullanılan bu yazılım geliştirme araçlarının tam olarak nasıl çalıştığına dair kafa yormuyor. Fundamental kavramlar üzerinde durmaktan ziyade, kodum çalışıyor mu sorusuna “evet” cevabı veriliyorsa sonuç yeterli görülüyor. Bana göre doğru olmayan bu yaklaşım beraberinde iki farklı sorunu ortaya çıkartıyor.
1- Kullanılan tool / framework / api veya üçüncü parti yazılımlarda karşılaşılan hatada, hatanın çözümünün tespiti çok uzun süreler alabiliyor.
2- Uygulamaların performanslarında ciddi derecede düşüşler görülebiliyor.
Bu tür sorunlarla karşılaşmamak adına kullandığımız teknoloji ve/veya araçları kullanmadan önce ilgili teknoloji ve araçların resmî dökümanlarını dikkatli şekilde okumanızda fayda olduğunu düşünüyorum.
Şimdi artık asıl konumuza gelelim, Spring Security!
Spring Security veya Spring MVC Framework unu anlamak için öncelikle Java’ya ait başka teknolojik kavramları bilmemiz gerektiğini düşünüyorum. Bu kavramlara değinmeden Spring Security hakkında kelam etmenin doğru olmadığını düşünüyorum. Bu nedenle aşağıda yazılı kavramları iyi bilmek gerekiyor.
- Servlet Nedir?
- Servlet Container(s) Nedir?
- Filter Nedir?
- Filter Chain Nedir?
- Proxy Design Pattern Nedir?
Servlet
Client (istemci) ‘lar tarafından gönderilen istekleri karşılayan bir Java arayüzüdür. Servlet mimarisi ile HTTP ile atılan GET, POST, PUT, vs. istekleri karşılayabilir ve bu isteklere göre işlemler yapabilirsiniz.
Servlet’ler client tarafından gelen her request için bir Thread açarak ilgili Servlet’in init() methodunu call eder. İlgili init() methodu bir kere çalıştırıldıktan sonra HTTP isteği tipine göre doGet(), doPost(), doPut(), methodları çağırılır. İşlem başarılı bir şekilde gerçekleştikten sonra yine ilgili thread tarafından Servlet’in destroy() methodu çağırılarak Servlet’in bellekten silinmesi sağlanır. Servlet’ler kısaca her istek anında JVM tarafından gelen her istek için bir kere yaratılır ve işlem sonucunda bellekten silinir. Servlet arayüzünün kodları aşağıdaki gibidir.
public void init(ServletConfig config) throws ServletException;
public void service(ServletRequest req, ServletResponse res)throws ServletException, IOException;
public void destroy();
public String getServletInfo();
public ServletConfig getServletConfig();
}
Servlet ile ilgili daha fazla bilgi sahibi olmak istiyorsanız tıklayınız.
Servlet Container

Servlet’lerden bahsettiğimize göre artık bu Servlet’leri yöneten konteynırlardan bahsedebiliriz.
Yukarıda da bahsettiğim gibi istemci tarafından gelen her istek yeni bir Thread üzerinden Servlet’e gider. Burada istemcilerden gelen istekleri karşılayıp ilgili Servlet’lere yönlendiren orkestrasyon araçlarına Servlet Container denir. Sıkça duyduğumuz ama belki de pek azımız tarafından bilinen şey ise, Spring dünyasında bu Servlet Konteynırlar dahili olarak gelmektedir. Bu sayede ayrıca bir Servlet Konteynırı yüklemenize gerek kalmadan Servletlerinizi yönetebilirsiniz.
Filter Nedir?
Filter denilince aslında aklımıza şöyle bir şey gelebilir. Diyelim ki elimizde bir 1 kg kadar pirinç var ve pirinçi ayıklamak istiyoruz. İçerisinde pirinç dışında başka şeyler olabilir, ufak taşlar veya farklı şeyler. Bunları ayıklamak için elek denilen bir alet kullanıyoruz. :)

Bu elek sayesinde aslında pirincimizin içerisinde olmasını istemediğimiz şeyleri ayıklıyoruz. Tam da bu açıdan bakıldığında, Filter sınıfı bu işe yarıyor. Client tarafından gelen istekleri server’a göndermeden önce bu Filter sınıfları sayesinde istek üzerinde bir çok işlem yapabiliyoruz. Örneğin istemciden gelen tüm istekleri trace etmek amacı ile NoSQL DB’sine yazmak isterseniz, buraya bir filter ekleyerek tüm istekleri processes etmeden önce işleyebiliriz.
Filter sınıfının kodlarını şuradan inceleyebilirsiniz.
Filter Chain
Filtre zinciri sayesinde birden çok filtreyi uygulayabilirsiniz. Yukarıdaki örnekte de bahsettiğimiz şekilde client tarafından gelen her istekte gelen isteğin bir kopyasını NoSQL DB’de tuttuktan sonra, isteğin Header’ında bazı alanları kontrol edebilirsiniz. Yine, authentication yapabilirsiniz. Yine gelen istekler üzerinde manipülasyonlar yapabilirsiniz. Kısaca, N adet filtreyi bir filtre zincirine ekleyerek, istek server tarafından process edilmeden önce bu zincire sokarak bir çok işlem yapabilirsiniz.
FilterChain sınıfının kodlarını şuradan inceleyebilirsiniz.
Proxy Design Pattern
Şu ana kadar anlattığım tüm başlıklar javax paketinden gelen ve Java EE spesifikasyonuydu. Bundan sonraki konular aslında design pattern ve bu design pattern ile Spring Mühendislerinin sorunları çözme biçimi ve bu Servlet API’ye kendi yaklaşımlarını nasıl entegre ettiklerini görebileceksiniz. Bu nedenle öncelikle Proxy Design Pattern üzerinden ilerleyelim.
Diyelim ki çok büyük bir şirketin CEO’’su olarak görev yapıyorsunuz. Şirket CEO’su olduğunuzda size bir çok birimden bir çok istek ve sorun gelecektir. Bu sorunların tamamı ile tek başınıza uğraşmak çok büyük zaman alabilir. Hatta bazen bazı sorunların siz değilde aslında sizin altınızda görev alan Direktör veya Manager’ların yapmasını isteyebilirsiniz. İşte tam olarak böyle bir durumla karşılaşıldığın Proxy Design Pattern hayatımızı kurtarıyor.

Yukarıda temas ettiğimiz konular Spring Security ile alakalı değil, daha çok Servlet API’nın basit anlatımı ve Proxy Design Pattern ile ilgiliydi. Şimdi Spring Security ’in tam olarak ne yaptığına gelelim.
FilterChainProxy Nedir?

Yukarıdaki hiyerarşiye baktığımızda, standart javax paketinde olmayan FilterChainProxy sınıfını görürüz. Sınıfın kaynak kodlarına baktığımızda, GenericFilterBean isimli sınıfı miras aldığını göreceğizdir. Spring bu sınıf ile FilterChain davranışını sergileyen bir sınıfı, Spring Bean sınıfına dönüştürüp, aslında @Bean anotasyonu ile işaretlenmiş sınıfların Filtre zincirine girmesini sağlamaktadır. Bu yaklaşım, Spring’in aslında sihir değil bir mühendislik harikası olduğunu gösteren başka bir detay olarak gözümüze çarpmakta. Peki, Spring bunu yaptıktan sonra ne yapıyor? Bean olarak işaretlenmiş sınıflarınızı Filtre zincirine ekleyerek, istekler işlenmeden önce filtrelerimizi uygulamamızı sağlıyor.
Şimdiye kadar Spring’in Servlet API’yi kullanarak nasıl davrandığını anladık. Şimdide Security kısmına girelim. Ayrıca şunu da belirtmek isterim ki, tüm ayrıntıları ile Security anlatmam mümkün değil. Elimden geldiğince Spring’in Security işini nasıl uyguladığını kuş bakışı ile anlatmak olacak. Gerisi size kalmış:)

- Filter’nin ne olduğunu yukarıda ayrıntılı şekilde anlattık. AuthenticationFilter ile istek filtreye sokuluyor. Request tipine göre BasicAuthenticationFilter , UsernamePasswordAuthenticationFilter gibi filtreler kullanılabilir.

- Filtreden geçen request başarılı olursa UsernamePasswordAuthenticationToken objesi oluşturulur.

- Oluşturulan token Authentication Manager sınıfına gönderilir ve ilgili token ile authenticate denenir. Burada dikkat etmeniz gereken bir şey var. authenticate methodu Authentication objesi alır ve Authentication objesi geri döner.

- Authenticatation objesi üzerinde bulunan Principal, GrantedAuthorities Authenticated objelerinin authenticate olmadan ve olduktan sonraki durumları değişmiştir.

- Authentication Manager sınıfını uygulayan bir ProviderManager sınıfı vardır. Bu sınıfın içersinde N adet Authentication Provider implementasyonları mevcuttur. Bunlardan bazıları ise Cas Authentication Provider, Dao Authentication Provider.

- Her provider sınıfının User Details Service özelliği vardır. User Detail Service sınıfının loadByUsername(String username) isimli bir methodu vardır. Bu method sayesinde kullanıcı bilgisini ilgili implementasyona göre doldurup kullanıcı bilgilerini bu obje üzerinde taşıyoruz. Yukarıdaki örneğimizden ilerlersek, Dao Authentication Provider sınıfı ile kullanıcı bilgilerini DB’den çekiyoruz. Yine dilerseniz In Memory olarakta çekebiliriz.

- User Details Servis sınıfının sorumluluğu gelen istek içerisindeki user bilgisi ile ilgili implementasyona göre bulacağımız kullanıcı bilgilerini karşılaştırarak kullanıcı bilgilerinin doğru olup olmadığına karar vermektir.
Security kısmı ile ilgili olarak Spring’in resmî dökümanına buradan ulaşabilirsiniz. Dilerseniz oradan çok daha ayrıntılı olarak Spring Security’i inleyebilirsiniz.
Bir sonraki medium yazımda görüşmek üzere,