Gereksinimler ve Ön Hazırlık
Uygulamaya başlamadan önce sisteminizde aşağıdaki araçların ve kütüphanelerin yüklü olduğundan emin olmalısınız. Spring Security'nin güncel sürümleri, Java 17 ve üzerini zorunlu kılmaktadır.
- JDK 17 veya 21: Uzun süreli destek (LTS) sürümleri.
- Spring Boot 3.4.x: Güncel bağımlılık yönetimi.
- Maven veya Gradle: Proje yapılandırma aracı.
- IDE: IntelliJ IDEA veya Eclipse.
Projenizin pom.xml dosyasına gerekli olan spring-boot-starter-security bağımlılığını ekleyerek işe başlayabiliriz.
org.springframework.boot
spring-boot-starter-security
SecurityFilterChain Yapılandırması
Spring Security 6.x ile birlikte WebSecurityConfigurerAdapter sınıfı kullanımdan kaldırılmıştır (deprecated). Artık güvenlik kurallarını bir SecurityFilterChain bean'i tanımlayarak yönetiyoruz. Bu yapılandırma, hangi sayfaların herkese açık, hangilerinin ise giriş gerektirdiğini belirler.
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/login", "/css/**", "/js/**").permitAll()
.anyRequest().authenticated()
)
.formLogin(form -> form
.loginPage("/login")
.defaultSuccessUrl("/dashboard", true)
.permitAll()
)
.logout(logout -> logout.permitAll());
return http.build();
}
}
Yukarıdaki kod bloğu, /login sayfasını herkesin görmesine izin verirken, diğer tüm isteklerin kimlik doğrulaması gerektirdiğini belirtir. formLogin ayarı ile özel bir login sayfası tanımlamış olduk.
Kullanıcı Bilgilerini Yönetmek: UserDetailsService
Kullanıcıların veritabanındaki bilgilerini Spring Security'nin anlayacağı bir formata dönüştürmemiz gerekir. Bunun için UserDetailsService arayüzünü implemente eden bir servis sınıfı oluşturmalıyız. Şifreleri asla düz metin olarak saklamamalı ve BCryptPasswordEncoder kullanmalıyız.
@Service
public class CustomUserDetailsService implements UserDetailsService {
@Autowired
private UserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findByUsername(username)
.orElseThrow(() -> new UsernameNotFoundException("Kullanıcı bulunamadı: " + username));
return org.springframework.security.core.userdetails.User
.withUsername(user.getUsername())
.password(user.getPassword())
.roles(user.getRole())
.build();
}
}
Bu servis, veritabanından kullanıcıyı çeker ve Spring Security'nin doğrulama yapabileceği bir UserDetails nesnesine dönüştürür. Güvenlik gereği, burada şifre karşılaştırması yapılmaz; sadece veriler hazırlanır.
Şifre Güvenliği ve PasswordEncoder
Şifrelerin veritabanında güvenli bir şekilde saklanması için PasswordEncoder kullanımı zorunludur. 2026 yılı itibarıyla BCrypt veya Argon2 algoritmaları önerilmektedir.
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
Bu bean, hem kullanıcı kaydederken şifreyi hashlemek (tek yönlü şifreleme) hem de login sırasında girilen şifreyi doğrulamak için kullanılır.
Kritik Uyarı: Şifreleri asla veritabanında düz metin (plain-text) olarak saklamayın. SQL Injection saldırılarına karşı her zaman Spring Data JPA'nın sunduğu parametreli sorguları veya Repository arayüzlerini kullanın.
Login Sayfası ve Thymeleaf Entegrasyonu
Login formunuzun Spring Security ile uyumlu olması için POST metodunu kullanması ve username ile password isimli input alanlarına sahip olması gerekir. Spring Security, varsayılan olarak bu alanları bekler.
Kullanıcı Adı:
Şifre:
Giriş Yap
Formun th:action="@{/login}" kısmı, Spring Security'nin varsayılan login işleme rotasına veri gönderir. CSRF (Cross-Site Request Forgery) koruması aktif olduğu için, form içerisinde otomatik olarak bir CSRF token'ı gizli input olarak eklenecektir.
Güvenlik Yöntemleri Karşılaştırma Tablosu
| Yöntem | Avantajı | Dezavantajı |
|---|---|---|
| Form Bazlı | Kullanıcı dostu, özelleştirilebilir | Session yönetimi gerektirir |
| Basic Auth | Basit, hızlı kurulum | Güvenlik düzeyi düşük, cache'lenebilir |
| JWT (Token) | Stateless, mobil uyumlu | Token saklama ve iptal etme zorluğu |
Sıkça Sorulan Sorular
Login olduktan sonra neden 403 hatası alıyorum?
Bu genellikle CSRF korumasının aktif olmasından kaynaklanır. Formunuzda th:action kullanıyorsanız, Thymeleaf otomatik olarak CSRF token'ını ekler. Eğer düz HTML kullanıyorsanız, token'ı manuel eklemelisiniz.
Şifreleri nasıl veritabanına kaydedebilirim?
Kullanıcı kayıt formundan gelen şifreyi passwordEncoder.encode(rawPassword) metodundan geçirerek hashlemeli ve ardından veritabanına kaydetmelisiniz.
Oturum süresini nasıl ayarlarım?
application.properties dosyasında server.servlet.session.timeout=30m ayarını kullanarak oturum süresini 30 dakika olarak belirleyebilirsiniz.
Logout nasıl yapılır?
SecurityFilterChain içinde tanımladığınız logout rotasına bir link vererek yapabilirsiniz. /logout varsayılan olarak Spring Security tarafından işlenir.
Birden fazla rolü nasıl yönetirim?
authorizeHttpRequests kısmında .requestMatchers("/admin/**").hasRole("ADMIN") gibi kurallar ekleyerek yetkilendirmeyi detaylandırabilirsiniz.
Sorumluluk Reddi: Bu rehberdeki kod örnekleri eğitim amaçlıdır. Üretim ortamında (production) kullanmadan önce HTTPS protokolünü zorunlu kılmalı, güvenlik açıklarını tarayan araçlar kullanmalı ve güncel güvenlik yamalarını takip etmelisiniz.
Spring Security ile Test Süreçleri ve Mocking
Uygulamanızın güvenlik katmanını geliştirdikten sonra, bu katmanın beklendiği gibi çalıştığından emin olmak için entegrasyon testleri yazmak kritik öneme sahiptir. Spring Security, spring-security-test kütüphanesi ile test süreçlerini oldukça kolaylaştırır. Özellikle @WithMockUser anotasyonu, gerçek bir veritabanı sorgusu yapmadan belirli rollerle sisteme giriş yapmış bir kullanıcıyı simüle etmenizi sağlar.
Aşağıdaki örnek, belirli bir URL'nin sadece yetkili kullanıcılar tarafından erişilebilir olduğunu doğrulayan bir test sınıfını göstermektedir:
@SpringBootTest
@AutoConfigureMockMvc
public class SecurityIntegrationTest {
@Autowired
private MockMvc mockMvc;
@Test
@WithMockUser(username = "admin", roles = {"ADMIN"})
public void adminEndpoint_ShouldBeAccessibleByAdmin() throws Exception {
mockMvc.perform(get("/admin/dashboard"))
.andExpect(status().isOk());
}
@Test
@WithMockUser(username = "user", roles = {"USER"})
public void adminEndpoint_ShouldReturnForbiddenForUser() throws Exception {
mockMvc.perform(get("/admin/dashboard"))
.andExpect(status().isForbidden());
}
}
Güvenlik Hata Ayıklama (Debugging) ve Loglama
Spring Security yapılandırmasında yapılan hatalar genellikle "403 Forbidden" veya "401 Unauthorized" gibi genel hatalara yol açar. Hatanın tam olarak hangi filtre zincirinde veya kuralda oluştuğunu anlamak için Spring Security'nin hata ayıklama modunu aktif edebilirsiniz. Bu mod, her istekte hangi filtrelerin çalıştığını ve güvenlik kurallarının nasıl değerlendirildiğini konsola yazdırır.
Hata ayıklama modunu aktif etmek için application.properties dosyanıza şu satırı ekleyin:
logging.level.org.springframework.security=DEBUG
Bu ayar ile birlikte konsol çıktılarında FilterSecurityInterceptor tarafından reddedilen isteklerin nedenlerini detaylıca görebilirsiniz. Eğer bir istek beklediğinizden farklı bir davranış sergiliyorsa, SecurityFilterChain içerisindeki requestMatchers sıralamasını kontrol etmeniz gerekebilir; çünkü Spring Security kuralları yukarıdan aşağıya doğru değerlendirir ve ilk eşleşen kuralı uygular.
İleri Düzey İpuçları
- CSRF Koruması: API odaklı geliştirmeler yapıyorsanız ve istemci tarafında (React/Angular) sorun yaşıyorsanız, CSRF token'larını
CookieCsrfTokenRepositorykullanarak istemciye iletebilirsiniz. - Oturum Sabitleme (Session Fixation): Spring Security varsayılan olarak oturum sabitleme saldırılarına karşı koruma sağlar. Kullanıcı giriş yaptığında eski oturum kimliğini geçersiz kılar ve yeni bir tane oluşturur. Bu ayarı
sessionManagement()üzerinden özelleştirebilirsiniz. - Güvenli Başlıklar: Uygulamanızın HTTP yanıtlarına otomatik olarak
X-Content-Type-OptionsveyaStrict-Transport-Securitygibi güvenlik başlıklarını eklemek içinhttp.headers()yapılandırmasını kullanın.
Sonuç
Java ile Spring Security kullanarak form bazlı login mekanizmasını kurmak, uygulamanızın güvenliğini sağlamak için attığınız en önemli adımdır. Bu rehberde, yapılandırma sınıfından kullanıcı detay servisine, şifreleme yöntemlerinden form entegrasyonuna kadar süreci adım adım inceledik. Bir sonraki adım olarak, uygulamanıza "Beni Hatırla" (Remember-Me) özelliğini ekleyebilir veya OAuth2 entegrasyonu ile sosyal medya hesaplarıyla giriş yapma yöntemlerini araştırabilirsiniz.

Yorumlar (0)
Yorum Yaz