Spring Boot, LDAP kimlik doğrulamasını JWE ile şifrelenmiş JWT’lerle birleştirerek API’larınızı hem external directory hem de token gizliliğiyle güvence altına almanızı sağlar.
Yazan
Şuayb Şimşek
Spring Boot, güvenlik, mikroservis ve cloud-native mimari konularında pratik teknik notlar paylaşan backend odaklı fullstack geliştirici.
# 1) Root DN
dn: dc=suaybsimsek,dc=com
objectClass: top
objectClass: domain
objectClass: extensibleObject
dc: suaybsimsek
# 2) People OU
dn: ou=people,dc=suaybsimsek,dc=com
objectClass: top
objectClass: organizationalUnit
ou: people
# 3) Admin user
dn: uid=admin,ou=people,dc=suaybsimsek,dc=com
objectClass: top
objectClass: person
objectClass: inetOrgPerson
cn: Admin User
sn: User
uid: admin
userPassword: $2a$10$sva6wl8pmGKJE6NIWrxwcuJK1Jaa2I/LOI43iHVpbR4YB8KjGViiK
# 4) Normal user
dn: uid=user,ou=people,dc=suaybsimsek,dc=com
objectClass: top
objectClass: person
objectClass: inetOrgPerson
cn: Normal User
sn: User
uid: user
userPassword: $2a$10$5Py4PyteLuXEqnGpSigzfu0V55C7Hi7zX18lmh.J8Bpmft.h23voG
# 5) Groups OU
dn: ou=groups,dc=suaybsimsek,dc=com
objectClass: top
objectClass: organizationalUnit
ou: groups
# 6) USER group → maps to ROLE_USER
dn: cn=USER,ou=groups,dc=suaybsimsek,dc=com
objectClass: top
objectClass: groupOfUniqueNames
cn: USER
uniqueMember: uid=user,ou=people,dc=suaybsimsek,dc=com
uniqueMember: uid=admin,ou=people,dc=suaybsimsek,dc=com
# 7) ADMIN group → maps to ROLE_ADMIN
dn: cn=ADMIN,ou=groups,dc=suaybsimsek,dc=com
objectClass: top
objectClass: groupOfUniqueNames
cn: ADMIN
uniqueMember: uid=admin,ou=people,dc=suaybsimsek,dc=com
Bu yapılandırma, tanımlı şema ile embedded bir LDAP sunucusunu ayağa kaldırır ve JWE imzalama ile şifreleme için RSA anahtarlarını yükler. Artık Spring Security’yi LDAP kimlik doğrulaması ve JWE tabanlı token oluşturma için yapılandırabilirsiniz.
🛠️ Adım 3: Güvenlik Yapılandırması
Bu bölümde, LDAP kimlik doğrulamasını yapılandırmak, RSA anahtarlarını ayarlamak ve JWE tabanlı kimlik doğrulama için HTTP güvenlik filtrelerini uygulamak üzere gerekli bean’leri ve özellikleri tanımlıyoruz:
JwtProperties: JWT encoder/decoder için imzalama ve şifreleme anahtar çiftlerini, issuer bilgisini ve expire süresini tanımlar.
SecurityConfig: Embedded LDAP kimlik doğrulamasını tanımlar ve stateless bir güvenlik filtresi zinciri kurarak ilgili URL’leri yetkilendirmeye tabi tutar.
SecurityJwtConfig
SecurityConfig
JwtProperties
UserProperties
🛠️ Adım 4: Güvenli JWE Token Yardımcı Sınıfları Oluşturun
Bu bölümde, Spring Boot uygulamanızda JSON Web Encryption (JWE) tokenları oluşturmak, şifrelemek ve çözmek için gereken temel yardımcı sınıfları ve sabitleri tanımlıyoruz. Bu bileşenler şunları sağlar:
AuthoritiesConstants: ROLE_ ön ekiyle rol isimlerini merkezileştirir.
CookieBearerTokenResolver: Bearer token’ları yetkilendirme başlıklarından veya HTTP çerezlerinden çözer.
CookieUtils: Erişim token’ları için HTTP-only ve secure çerezler oluşturur.
JweUtil: Nimbus kütüphanesi ile RSA anahtarları kullanarak JWT’leri imzalar (JWS) ve şifreler (JWE).
KeyUtils: PEM formatındaki anahtar çiftinden RSA JWK’leri oluşturur.
SecurityUtils: SecurityContext oturum açan kullanıcının bilgisini sunar.
Bu yardımcılar, Spring Security ile durumsuz (stateless) JWE tabanlı bir kimlik doğrulama akışının temelini oluşturur.
AuthoritiesConstants
CookieBearerTokenResolver
CookieUtils
JweUtil
KeyUtils
SecurityUtils
🧪 Adım 5: Kimlik Doğrulama ve Güvenli Endpointler
Bu bölümde, aşağıdakileri gerçekleştirmek için gerekli REST controller ve DTO’ları tanımlıyoruz:
AuthController: Kullanıcıları doğrular, JWE token’ları oluşturur ve güvenli cookie ayarlar.
HelloController: Kimliği doğrulanmış kullanıcılar ve yalnızca admine özel pathler için güvenli endpointler sunar.
LoginRequestDTO: Login isteği payloadını (kullanıcı adı/parola) modelleyen DTO.
TokenDTO: Token ve geçerlilik süresini içeren kimlik doğrulama yanıtını modelleyen DTO.
Bu bileşenler, login işlemi, token oluşturma, cookie yönetimi ve kaynak korumasını işleyerek stateless(durumsuz) kimlik doğrulama akışını tamamlar.
Bu bölümde, kullanıcı kimlik doğrulamasını, token oluşturmayı ve korunan kaynak erişimini yönetmek için REST controller ve DTO’ları oluşturuyoruz.
AuthController
HelloController
LoginRequestDTO
TokenDTO
▶️ Uygulamayı Çalıştır
BASH
./mvnw spring-boot:run
# or
gradle bootRun
🧪 Endpoint Testi
Bu bölümde Endpoint Testi konusunu netleştirip uygulamada kullanacağınız temel noktaları özetliyoruz.
Admin Akışı
admin olarak giriş yapın ve Set-Cookie başlığından JWE tokeni yakalayın:
Artık Spring Boot LDAP ve JWE Kimlik Doğrulama için üretim odaklı bir Spring Boot temeliniz var. Sonraki adımda ayarları kendi domainine uyarlayıp test ve gözlemlenebilirlik katmanını ekleyerek gerçek trafik altında doğrulayın.
package io.github.susimsek.springbootldapjwedemo.config
import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.context.annotation.Configuration
@Configuration
@ConfigurationProperties(prefix = "security.user")
class UserProperties {
lateinit var username: String
lateinit var password: String
}
JAVAAuthoritiesConstants.java
package io.github.susimsek.springbootldapjwedemo.security;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public final class AuthoritiesConstants {
public static final String ADMIN = "ROLE_ADMIN";
public static final String USER = "ROLE_USER";
public static final String ANONYMOUS = "ROLE_ANONYMOUS";
}
KOTLINAuthoritiesConstants.kt
package io.github.susimsek.springbootldapjwedemo.security
object AuthoritiesConstants {
const val ADMIN = "ROLE_ADMIN"
const val USER = "ROLE_USER"
const val ANONYMOUS = "ROLE_ANONYMOUS"
}
package io.github.susimsek.springbootldapjwedemo.controller;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.web.bind.annotation.*;
import static io.github.susimsek.springbootldapjwedemo.security.SecurityUtils.AUTHORITIES_KEY;
@RestController
@RequestMapping("/api/hello")
public class HelloController {
@GetMapping
public String helloAll(@AuthenticationPrincipal Jwt jwt) {
String user = jwt.getSubject();
var roles = jwt.getClaimAsStringList(AUTHORITIES_KEY);
return "Hello, " + user + "! Your roles: " + roles;
}
@GetMapping("/admin")
public String helloAdmin(@AuthenticationPrincipal Jwt jwt) {
return "Hello Admin, " + jwt.getSubject() + "!";
}
}
KOTLINHelloController.kt
package io.github.susimsek.springbootldapjwedemo.controller
import org.springframework.security.core.annotation.AuthenticationPrincipal
import org.springframework.security.oauth2.jwt.Jwt
import org.springframework.web.bind.annotation.*
import io.github.susimsek.springbootldapjwedemo.security.SecurityUtils.AUTHORITIES_KEY
@RestController
@RequestMapping("/api/hello")
class HelloController {
@GetMapping
fun helloAll(@AuthenticationPrincipal jwt: Jwt): String {
val user = jwt.subject
val roles = jwt.getClaimAsStringList(AUTHORITIES_KEY)
return "Hello, \$user! Your roles: \$roles"
}
@GetMapping("/admin")
fun helloAdmin(@AuthenticationPrincipal jwt: Jwt): String {
return "Hello Admin, \${jwt.subject}!"
}
}
JAVALoginRequestDTO.java
package io.github.susimsek.springbootldapjwedemo.dto;
public record LoginRequestDTO(
String username,
String password
) { }
KOTLINLoginRequestDTO.kt
package io.github.susimsek.springbootldapjwedemo.dto
data class LoginRequestDTO(
val username: String,
val password: String
)
JAVATokenDTO.java
package io.github.susimsek.springbootldapjwedemo.dto;
public record TokenDTO(
String accessToken,
String tokenType,
long accessTokenExpiresIn
) {}
KOTLINTokenDTO.kt
package io.github.susimsek.springbootldapjwedemo.dto
import kotlin.Long
data class TokenDTO(
val accessToken: String,
val tokenType: String,
val accessTokenExpiresIn: Long
)