Yetkilendirme Yaklaşımları
İçindekiler
- Yetkilendirme
- Yetkilendirme Nedir?
- Yetkilendirme Mekanizmasının Temelleri
- Spring Security Yapılandırması
- Yetkilendirme Anotasyonları
- Kullanıcı ve Roller
- Spring Security Yetkilendirme Mimarisi
- Çağrı Yönetimi
- Kaynakça
Giriş
Güvenli yazılım geliştirme sürecinde yetkilendirme (authorization), yalnızca kimlik doğrulaması yapılmış kullanıcıların değil, aynı zamanda doğru izinlere sahip kullanıcıların da belirli kaynaklara veya işlemlere erişmesini sağlayan temel bir güvenlik katmanıdır. Eksik veya hatalı tasarlanmış yetkilendirme mekanizmaları, sistemin bütünlüğünü, gizliliğini ve güvenilirliğini tehdit eden ciddi güvenlik açıklarına yol açabilir. Bu nedenle, modern uygulamalarda esnek, ölçeklenebilir ve yönetilebilir yetkilendirme stratejileri geliştirmek kritik öneme sahiptir.
Bu yazıda, Spring Security çerçevesinde yetkilendirme süreçlerini adım adım ele alacağız. İlk olarak yetkilendirme kavramının temellerini ve yapı taşlarını açıklayacak, ardından SecurityFilterChain ile nasıl yapılandırma yapılacağını göstereceğiz. Yöntem düzeyinde yetkilendirme anotasyonları (@PreAuthorize, @Secured) ile hassas erişim kontrollerinin nasıl sağlanabileceğini inceleyeceğiz. Devamında Spring Security’nin yetkilendirme mimarisi, GrantedAuthority yapısı, AuthorizationManager arayüzü ve farklı implementasyonları üzerinde duracağız. Son bölümde ise gerçek dünyadaki karmaşık senaryolar için özel AuthorizationManager geliştirme yaklaşımlarını örneklerle açıklayacağız.
Yetkilendirme
Yetkilendirme Nedir?
Yetkilendirme, bir kullanıcının belirli kaynaklara veya eylemlere erişim iznine sahip olup olmadığını kontrol etme işlemidir[1]. Spring Security, yetkilendirmeyi konfigürasyon veya anotasyonlar aracılığıyla sağlamayı kolaylaştırır.
Yetkilendirme Mekanizmasının Temelleri
Yetkilendirme, genellikle kullanıcıların rollerine veya izinlerine göre yapılandırılır[1]. Spring Security, kullanıcının sahip olduğu yetkileri (örn. ROLE_USER, ROLE_ADMIN) kontrol ederek belirli endpoint’lere (uç noktalara) erişimi sağlar veya engeller.
Spring Security Yapılandırması
Spring Security’nin modern yapılandırması için SecurityFilterChain kullanarak bir güvenlik yapılandırması oluşturabiliriz[1].
Örnek Konfigürasyon
Aşağıda, basit bir Spring Boot uygulamasında form tabanlı oturum açma ve yetkilendirme yapılandırması örneği verilmiştir:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(authorize -> authorize
.antMatchers("/public/**").permitAll() // Bu endpoint'ler herkese açık
.antMatchers("/admin/**").hasRole("ADMIN") // Yalnızca ADMIN rolüne sahip kullanıcılar erişebilir
.anyRequest().authenticated() // Diğer tüm endpoint'ler için oturum açmış kullanıcı gereklidir
)
.formLogin(form -> form
.loginPage("/login") // Özel oturum açma sayfası
.permitAll()
)
.logout(logout -> logout
.logoutUrl("/logout")
.permitAll()
);
return http.build();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(); // Şifrelerin güvenli bir şekilde saklanması için BCrypt kullanılır
}
}
Yetkilendirme Anotasyonları
Spring Security, yöntem düzeyinde yetkilendirmeyi sağlamak için anotasyonlar kullanmanıza da olanak tanır[2]:
- @PreAuthorize: Bir yöntem çağrılmadan önce yetkilendirme kontrolü yapar.
- @Secured: Belirli rollere göre erişimi kısıtlar.
Örnek Kullanım
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Service
public class SampleService {
@PreAuthorize("hasRole('ADMIN')")
public void adminMethod() {
// Bu yöntem sadece ADMIN rolüne sahip kullanıcılar tarafından çağrılabilir
System.out.println("Admin yetkili işlem gerçekleştirildi.");
}
@Secured("ROLE_USER")
public void userMethod() {
// Bu yöntem sadece USER rolüne sahip kullanıcılar tarafından çağrılabilir
System.out.println("Kullanıcı yetkili işlem gerçekleştirildi.");
}
}
Kullanıcı ve Roller
Uygulamada kullanıcı ve roller genellikle veri tabanında saklanır. Spring Security, bu kullanıcı bilgilerini almak için UserDetailsService arabirimini sağlar[3].
Örnek Kullanıcı Detayları Servisi:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@Service
public class CustomUserDetailsService implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
// Bu örnekte sabit bir kullanıcı tanımlandı, genellikle veri tabanından çekilir.
if ("admin".equals(username)) {
return User.builder()
.username("admin")
.password(new BCryptPasswordEncoder().encode("password"))
.roles("ADMIN")
.build();
} else if ("user".equals(username)) {
return User.builder()
.username("user")
.password(new BCryptPasswordEncoder().encode("password"))
.roles("USER")
.build();
} else {
throw new UsernameNotFoundException("Kullanıcı bulunamadı: " + username);
}
}
}
Spring Security Yetkilendirme Mimarisi
Yetkiler
Spring Security’nin yetkilendirme mimarisi, yetkilerin nasıl yönetildiğini ve kullanıldığını tanımlar. GrantedAuthority nesneleri, kullanıcıların sahip olduğu yetkileri temsil eder. Bu nesneler, AuthenticationManager tarafından Authentication nesnesine eklenir ve daha sonra AccessDecisionManager tarafından yetkilendirme kararları almak için kullanılır.
GrantedAuthority Arayüzü
Tek bir metod içerir: getAuthority(), yetkinin String temsili için kullanılır. Spring Security, SimpleGrantedAuthority sınıfı ile bu arayüzün bir implementasyonunu sağlar, bu da kullanıcı tanımlı String’lerin yetki olarak kullanılmasına olanak tanır.
Rol Tabanlı Yetkilendirme: Varsayılan olarak, rol tabanlı yetkilendirme için “ROLE_” öneki kullanılır. Örneğin, “USER” rolü için GrantedAuthority#getAuthority metodu “ROLE_USER” döner.
GrantedAuthorityDefaults ile bu önek değiştirilebilir. Bir örnek bean(Spring tarafından yönetilen nesne) tanımı şu şekildedir:
1
2
3
4
@Bean
static GrantedAuthorityDefaults grantedAuthorityDefaults() {
return new GrantedAuthorityDefaults("MYPREFIX_");
}
Çağrı Yönetimi
Spring Security, yöntem çağrıları veya web istekleri gibi güvenli nesnelere erişimi kontrol eden interceptor’lar(Yakalayıcı/Araya Girici bileşen) sağlar. Bir çağrının devam edip edemeyeceğine dair önceden bir karar, AuthorizationManager örnekleri tarafından verilir. Ayrıca, belirli bir değerin döndürülüp döndürülemeyeceğine dair karar da AuthorizationManager tarafından verilir.
AuthorizationManager
- Spring AuthorizationManager, kimlik doğrulaması yapılmış bir varlığın güvenli bir kaynağa erişim hakkı olup olmadığını kontrol etmemize olanak tanıyan bir arayüzdür. Spring Security, istek tabanlı, metod tabanlı ve mesaj tabanlı bileşenler için nihai erişim kontrol kararlarını almak amacıyla AuthorizationManager örneklerini kullanır.
AuthorizationManager öncesinde bazı önemli Spring Security kavramlarını anlamak faydalı olacaktır:
- Varlık (Entity): Sisteme istek yapabilen her şeydir. Bu, örneğin bir insan kullanıcısı veya uzaktaki bir web servisi olabilir.
- Kimlik Doğrulama (Authentication): Bir varlığın iddia ettiği kişi olduğunu doğrulama sürecidir. Bu, kullanıcı adı/şifre, token veya başka yöntemler aracılığıyla yapılabilir.
- Yetkilendirme (Authorization): Bir varlığın bir kaynağa erişim hakkı olup olmadığını doğrulama sürecidir.
- Kaynak (Resource): Sistemin erişime sunduğu herhangi bir bilgi; örneğin, bir URL veya belge.
- Yetki (Authority): Genellikle Rol olarak adlandırılan, bir varlığın sahip olduğu izinleri temsil eden mantıksal bir addır. Tek bir varlığa sıfır veya daha fazla yetki verilebilir.
AuthorizationManager Nasıl Kullanılır?
AuthorizationManager, yalnızca iki metod içeren basit bir arayüzdür:
1
2
3
AuthorizationDecision check(Supplier<Authentication> authentication, T object);
void verify(Supplier<Authentication> authentication, T object);
Her iki metot da benzer görünse de, farklı amaçlara hizmet eder ve aynı argümanları alır:
- authentication: İstek yapan varlığı temsil eden Authentication nesnesini sağlayan bir Supplier.
- object: İstenen güvenli nesne (isteğin türüne göre değişiklik gösterebilir).
Metotların Amaçları
- check Metodu: Bu metod, güvenli nesneye erişim izni olup olmadığını belirten bir AuthorizationDecision döner. AuthorizationDecision, bir boolean değerin etrafını saran basit bir sınıftır ve varlığın erişim izni olup olmadığını gösterir.
- verify Metodu: Bu metod ise herhangi bir değer döndürmez. Bunun yerine, yetkilendirme kontrolünü yapar ve varlık güvenli nesneye erişim yetkisine sahip değilse AccessDeniedException fırlatır. Bu metotlar, sistemdeki isteklerin yetkilendirme süreçlerini yönetmek için kullanılır ve Spring Security’nin farklı bileşenlerinde yetkilendirme kontrolleri yapar[4], [5].
AuthorizationManager İmplementasyonları
Şekil 1’de, Spring Security’nin AuthorizationManager arayüzü ve ondan türeyen farklı yetkilendirme yöneticisi implementasyonları gösterilmektedir. Bu yapı, farklı yetkilendirme senaryoları için özelleşmiş kontrol mekanizmalarının nasıl çeşitlendiğini görselleştirmektedir.
AuthenticatedAuthorizationManager (Kimlik Doğrulama Bazlı)
En basit AuthorizationManager implementasyonlar’ından biridir. Bu sınıf, varlığın kimlik doğrulamasına dayanarak pozitif bir yetkilendirme kararı döner.
Bu, web tabanlı uygulamalar için Spring Boot’un varsayılan olarak oluşturduğu AuthorizationManager’dır. Varsayılan olarak, tüm uç noktalar, kimlik doğrulanmış bir varlık olduğu sürece rol veya yetkiden bağımsız olarak erişime izin verir.
AuthenticatedAuthorizationManager, kimliğin doğrulanıp doğrulanmadığını kontrol ederken, remember-me veya anonymous gibi durumları da dikkate alabilir. İstenirse yalnızca tam oturum (fully authenticated) durumlarına izin vermek için AuthenticatedAuthorizationManager.fullyAuthenticated() gibi yöntemler kullanılabilir.
AuthoritiesAuthorizationManager (Çoklu Rol/Yetki)
Bu kararlarını birden fazla yetkiye dayanarak verebilir. Kaynakların birden fazla yetki tarafından erişilebilir olması gerektiği daha karmaşık uygulamalar için uygundur.
Örneğin, bir blog sisteminde, makale oluşturma ve kaydetme işlemi hem Yazar hem de Editör rolleri için erişilebilir olabilir. Ancak, yayına alma işlemi yalnızca Editör rolü için mevcut olabilir.
AuthorityAuthorizationManager
Bu uygulama oldukça basittir ve yetkilendirme kararlarını tamamen varlığın belirli bir role sahip olup olmamasına göre verir. Her kaynağın yalnızca tek bir rol veya yetki gerektirdiği basit uygulamalar için uygundur.
Örneğin, belirli bir URL kümesini yalnızca Yönetici rolüne sahip varlıkların erişimine açmak için kullanılabilir. Bu uygulama, karar verme işlemini bir AuthoritiesAuthorizationManager örneğine devreder. Ayrıca, SecurityFilterChain yapılandırmasında hasRole() veya hasAuthority() çağrıldığında Spring’in kullandığı uygulamadır.
RequestMatcherDelegatingAuthorizationManager (Yola Göre Delegasyon)
Bu sınıf, uygulamanızda belirli yolların farklı yetkilendirme kurallarıyla kontrol edilmesini sağlar. Örneğin, bazı URL’lerin herkese açık olmasını, bazı URL’lerin ise sadece belirli rollere sahip kullanıcılara açık olmasını sağlayabilirsiniz. Gelen bir HTTP isteğini belirli URL desenleriyle eşleştirir ve bu desenlerle ilişkili AuthorizationManager’a devreder. Bu sayede, farklı URL’ler için farklı yetkilendirme mantıkları uygulanabilir. Bu, Spring’in SecurityFilterChain yapılandırmasına yeni bir istek eşleyici eklediğimizde yaptığı işlemdir. Her yeni istek eşleyici yapılandırıldığında ve bir veya daha fazla gerekli rol veya yetki belirtildiğinde, Spring bu sınıfın yeni bir örneğini ve uygun bir temsilci oluşturur.
Çoklu AuthorizationManager Kullanımı
Pratikte, genellikle tek bir AuthorizationManager örneği kullanmayız. Aşağıdaki SecurityFilterChain bean örneğine bir göz atalım:
1
2
3
4
5
6
7
8
@Bean
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests((authorize) -> authorize
.requestMatchers("/posts/publish/**").hasRole("EDITOR")
.requestMatchers("/posts/create/**").hasAnyRole("EDITOR", "AUTHOR")
.anyRequest().permitAll());
return http.build();
}
Bu yapılandırma altında Spring, her requestMatcher, hasRole, hasAnyRole gibi çağrılar için farklı AuthorizationManager implementasyonları oluşturur ve kullanır. Böylece her endpoint’e(uç noktaya) özel yetkilendirme mantığı uygulanır.
Aşağıda bu çağrıların nasıl AuthorizationManager’lara dönüştüğü listelenmiştir:
- hasRole() çağrısı, bir AuthorityAuthorizationManager örneği oluşturur ve bu da yeni bir AuthoritiesAuthorizationManager örneğine devreder.
- hasAnyRole() çağrısı da bir AuthorityAuthorizationManager örneği oluşturur ve bu da yeni bir AuthoritiesAuthorizationManager örneğine devreder.
- permitAll() çağrısı, Spring Security tarafından sağlanan ve her zaman pozitif bir yetkilendirme kararı veren statik bir “no-op” AuthorizationManager kullanır.
- requestMatchers() çağrılarında RequestMatcherDelegatingAthorizationManager örneği kullanılır ve sonraki seçimlere göre uygun implementasyona iletilir. Bu yapı, çeşitli yollar için farklı yetkilendirme kuralları ve yöneticileri oluşturmanıza olanak tanır.
Özel Bir AuthorizationManager Kullanımı
Yukarıda belirtilen AuthorizationManager uygulamaları birçok uygulama için yeterlidir. Ancak, Spring’deki birçok arayüz gibi, kendi ihtiyaçlarınıza uygun bir özel AuthorizationManager oluşturmak tamamen mümkündür[4].
1
2
3
4
5
6
7
8
9
10
11
12
13
14
AuthorizationManager<RequestAuthorizationContext> customAuthManager() {
return new AuthorizationManager<RequestAuthorizationContext>() {
@Override
public AuthorizationDecision check(Supplier<Authentication> authenticationSupplier, RequestAuthorizationContext context) {
Authentication authentication = authenticationSupplier.get();
String path = context.getRequest().getRequestURI();
boolean isAuthorized = authentication != null && authentication.isAuthenticated()
&& path.startsWith("/admin");
return new AuthorizationDecision(isAuthorized);
}
};
}
Bu örnekte, yetkilendirme kararını RequestAuthorizationContext kullanarak alıyoruz. Bu sınıf, temel HTTP isteğine erişim sağlar ve böylece çerezler, başlıklar ve daha fazlası gibi faktörlere dayanarak kararlar alınmasına olanak tanır.
Daha sonra bu özel AuthorizationManager örneğini SecurityFilterChain yapılandırmasında kullanabiliriz:
1
2
3
4
5
6
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests((authorize) ->
authorize.requestMatchers("/custom/**").access(customAuthManager())
);
return http.build();
}
Bu durumda, RequestAuthorizationContext kullanarak yetkilendirme kararları alıyoruz. Bu yapı, belirli çerezler veya başlıklar gibi HTTP isteği bileşenlerine dayanarak özelleştirilmiş yetkilendirme kuralları oluşturmanıza olanak tanır. Ayrıca, karar verme sürecini üçüncü taraf bir servise, bir veri tabanına veya önbelleğe devredebilir ve çeşitli yapılar kullanarak farklı yetkilendirme kararları verebilirsiniz.
Bu yapı, Spring Security’nin esnekliğini artırarak özel ihtiyaçlarınıza göre özelleştirilebilir yetkilendirme kontrolleri oluşturmanıza olanak sağlar.
*Bu yazının hazırlanmasında katkı sağlayan teknik gözden geçirme için Rabia Nur ÖNAL’a ve Ahmet Burak KAPLAN’a, içerik düzenlemelerinde destek sunan Kübra ERTÜRK’e teşekkür ederiz. Sağladıkları geri bildirimler, yazının hem teknik doğruluğunu hem de okunabilirliğini artırmada önemli rol oynamıştır.
Kaynakça
[1] Spring, “Authorization,” Spring Security Reference Documentation, [Çevrimiçi]. Mevcut: https://docs.spring.io/spring-security/reference/servlet/authorization/index.html. [Erişim zamanı: Ağustos 15, 2025].
[2] Spring, “Method Security,” Spring Security Reference Documentation, [Çevrimiçi]. Mevcut: https://docs.spring.io/spring-security/reference/servlet/authorization/method-security.html. [Erişim zamanı: Ağustos 15, 2025].
[3] Spring, “UserDetailsService,” Spring Security Reference Documentation, [Çevrimiçi]. Mevcut: https://docs.spring.io/spring-security/reference/servlet/authentication/passwords/user-details.html. [Erişim zamanı: Ağustos 15, 2025].
[4] Spring, “Authorization Architecture,” Spring Security Reference Documentation, [Çevrimiçi]. Mevcut: https://docs.spring.io/spring-security/reference/servlet/authorization/architecture.html. [Erişim zamanı: Ağustos 15, 2025].
[5] Spring Security GitHub, “Spring Security Samples,” [Çevrimiçi]. Mevcut: https://github.com/spring-projects/spring-security. [Erişim zamanı: Ağustos 15, 2025].