Spring Security 6'yı kullanarak bir Spring Boot 3.0 uygulamasında JWT kimlik doğrulamasını ve yetkilendirmesini nasıl uygulayacağınızı öğreneceksiniz. JSON Web Tokens Adım adım kılavuzlarını kullanarak uygulamanızın güvenliğini sağlamanın ve uç noktalarınızı korumanın ne kadar kolay olduğunu göreceksiniz.
JWT nedir?
JWT veya JSON Web Token, iki taraf arasında güvenli bir şekilde aktarılacak talepleri temsil eden kompakt, bağımsız bir araçtır. Kimlik doğrulama ve yetkilendirme bağlamında, JWT genellikle kullanıcıların kimliğini doğrulamak ve onlara kaynaklara veya servislere erişim izni vermek için kullanılır. JWT'nin kimlik doğrulama ve yetkilendirmede nasıl çalıştığının bir dökümü aşağıda verilmiştir:
1. Kimlik Doğrulama JWT, başarılı oturum açma sonrasında kullanıcıya bir belirteç vererek kimlik doğrulama için kullanılabilir. Belirteç, kullanıcı hakkında, genellikle talepler biçimindeki bilgileri içerir. Bu iddialar kullanıcının kimliğini, kullanıcı adını, rolünü veya diğer ilgili bilgileri içerebilir. Süreç genellikle aşağıdaki adımları içerir:
- Kullanıcı kimlik bilgileriyle (örn. kullanıcı adı ve şifre) oturum açar. - Sunucu kullanıcının kimlik bilgilerini doğrular. - Başarılı kimlik doğrulamanın ardından sunucu, kullanıcı taleplerini içeren bir JWT oluşturur. - JWT daha sonra kullanıcının istemcisine (örneğin bir web tarayıcısına veya mobil uygulamaya) geri gönderilir. - İstemci, JWT'yi genellikle bir çerezde veya yerel depolamada güvenli bir şekilde saklar.
2. Yetkilendirme: JWT aynı zamanda yetkilendirme için de kullanılır ve sunucunun kullanıcının neye erişmesine izin verildiğini belirlemesine olanak tanır. JWT içindeki talepler kullanıcının rollerini, izinlerini veya diğer yetkilendirme bilgilerini belirtebilir. Yetkilendirme süreci genellikle aşağıdaki adımları içerir:
- Kullanıcının istemcisi, sunucudaki korumalı bir kaynağa istekte bulunur. - Sunucu isteği alır ve istek başlıklarında geçerli bir JWT'nin varlığını kontrol eder. - Geçerli bir JWT mevcutsa sunucu, kullanıcının kimliğini ve rollerini belirlemek için belirteç içindeki talepleri okuyabilir. - Kullanıcının taleplerine göre sunucu, kullanıcının istenen kaynağa erişim için gerekli izinlere sahip olup olmadığına karar verebilir. - Kullanıcı yetkilendirilmişse, sunucu kaynağa erişime izin verir; aksi takdirde erişimi reddeder.
JWT'ler, kendi kendine yeten ve vatansız oldukları için kimlik doğrulama ve yetkilendirme açısından avantajlıdır. Bu, sunucunun kullanıcı oturumlarını depolamasına gerek olmadığı anlamına gelir; bu da ölçeklendirmeyi ve bakımı kolaylaştırır. Ek olarak JWT'ler, bütünlüklerini ve özgünlüklerini sağlamak için dijital olarak imzalanabilir ve böylece kötü niyetli kişilerin kurcalaması önlenebilir.
Ancak JWT'leri güvenli bir şekilde yönetmek, jeton hırsızlığına karşı korumak ve kimlik doğrulama ve yetkilendirme süreçlerinde güvenilirliklerini sağlamak için uygun şifreleme ve doğrulama mekanizmalarını kullanmak çok önemlidir.
Hadi kodlamaya başlayalım :)
Öncelikle pom.xml dosyasında aşağıdaki maven bağımlılıklarına ihtiyacımız var:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.modelmapper/modelmapper -->
<dependency>
<groupId>org.modelmapper</groupId>
<artifactId>modelmapper</artifactId>
<version>3.1.1</version>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt-api -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.5</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt-impl -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.11.5</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt-jackson -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.11.5</version>
</dependency>
Aşağıdaki gibi bir JwtService sınıfı oluşturun:
@Component
public class JwtService {
public static final String SECRET = "357638792F423F4428472B4B6250655368566D597133743677397A2443264629";
public String extractUsername(String token) {
return extractClaim(token, Claims::getSubject);
}
public Date extractExpiration(String token) {
return extractClaim(token, Claims::getExpiration);
}
public <T> T extractClaim(String token, Function<Claims, T> claimsResolver) {
final Claims claims = extractAllClaims(token);
return claimsResolver.apply(claims);
}
private Claims extractAllClaims(String token) {
return Jwts
.parserBuilder()
.setSigningKey(getSignKey())
.build()
.parseClaimsJws(token)
.getBody();
}
private Boolean isTokenExpired(String token) {
return extractExpiration(token).before(new Date());
}
public Boolean validateToken(String token, UserDetails userDetails) {
final String username = extractUsername(token);
return (username.equals(userDetails.getUsername()) && !isTokenExpired(token));
}
public String GenerateToken(String username){
Map<String, Object> claims = new HashMap<>();
return createToken(claims, username);
}
private String createToken(Map<String, Object> claims, String username) {
return Jwts.builder()
.setClaims(claims)
.setSubject(username)
.setIssuedAt(new Date(System.currentTimeMillis()))
.setExpiration(new Date(System.currentTimeMillis()+1000*60*1))
.signWith(getSignKey(), SignatureAlgorithm.HS256).compact();
}
private Key getSignKey() {
byte[] keyBytes = Decoders.BASE64.decode(SECRET);
return Keys.hmacShaKeyFor(keyBytes);
}
}Kimlik doğrulama ve yetkilendirme için JSON Web Belirteçlerinin (JWT) kullanılması bağlamında, SECRET_KEYJWT'leri imzalamak ve doğrulamak için kullanılan gizli bir şifreleme anahtarıdır. Bu, yalnızca jetonları oluşturan ve doğrulayan sunucunun bildiği bir bilgi parçasıdır. Bu anahtar, JWT'lerin bütünlüğünü ve orijinalliğini sağlamak için çok önemlidir.
' JwtService ' sınıfı, bir Spring Boot uygulamasında JWT (JSON Web Tokens) ile ilgili çeşitli işlemlerden sorumlu bir bileşendir. JWT belirteçlerinin oluşturulması, ayrıştırılması ve doğrulanması için yöntemler içerir. Her yöntemi inceleyelim ve amacını açıklayalım:
1. public String extractUsername(String token): — Bu yöntem girdi olarak bir JWT belirtecini alır ve konuyu (genellikle kullanıcı adını) belirtecin taleplerinden çıkarır. Konu hak talebini çıkarmak için 'extractClaim' yöntemini kullanır.
2. public Date extractExpiration(String token): — Bu yöntem, JWT belirtecinin taleplerinden son kullanma tarihini çıkarır. Belirtecin süresinin dolup dolmadığını belirlemek için kullanılır.
3. public <T> T extractClaim(String token, Function<Claims, T>claimResolver): — Bu, JWT belirtecinin taleplerinden belirli bir talebi çıkarmak için kullanılan genel bir yöntemdir. Bir JWT jetonu ve istenen talebin (örn. konu veya son kullanma tarihi) nasıl çıkarılacağını belirten bir "İşlev" alır ve çıkarılan talebi döndürür.
4. Private Claims extractAllClaims(String token): — Bu yöntem JWT belirtecini ayrıştırır ve tüm taleplerini çıkarır. Uygun imzalama anahtarıyla yapılandırılmış bir ayrıştırıcı oluşturmak için 'Jwts' oluşturucusunu kullanır ve ardından belirtecin taleplerini çıkarır.
5. Private Boolean isTokenExpired(String token): — Bu yöntem, belirtecin son kullanma tarihini ('extractExpiration' kullanılarak elde edilir) geçerli tarihle karşılaştırarak bir JWT belirtecinin süresinin dolup dolmadığını kontrol eder. Belirtecin süresi dolmuşsa "true" değerini döndürür; aksi takdirde 'yanlış' değerini döndürür.
6. public Boolean validateToken(String token, UserDetails userDetails): — Bu yöntem bir JWT belirtecini doğrulamak için kullanılır. İlk önce kullanıcı adını belirteçten çıkarır ve ardından sağlanan 'UserDetails' nesnesinin kullanıcı adıyla eşleşip eşleşmediğini kontrol eder. Ayrıca belirtecin süresinin dolup dolmadığını da doğrular. Belirteç geçerliyse "true" değerini döndürür; aksi takdirde 'yanlış' değerini döndürür.
7. public String GenerateToken(String kullanıcı adı): — Bu yöntem bir JWT belirteci oluşturmak için kullanılır. Giriş olarak bir kullanıcı adı alır, bir dizi talep oluşturur (örn. konu, yayınlanma tarihi, sona erme tarihi) ve ardından talepleri ve imzalama anahtarını kullanarak bir JWT belirteci oluşturur. Ortaya çıkan jeton iade edilir.
8. Private String createToken(Map<String, Object> iddiaları, String kullanıcı adı): — Bu yöntem JWT belirtecinin oluşturulmasından sorumludur. Talepleri, konuyu, yayın tarihini, son kullanma tarihini ve imzalama anahtarını belirtmek için 'Jwts' oluşturucusunu kullanır. Token daha sonra imzalanır ve sıkıştırılarak iade edilen son JWT tokeni üretilir.
9. Private Key getSignKey(): — Bu yöntem, JWT belirteci oluşturma ve doğrulama için imzalama anahtarını elde etmek amacıyla kullanılır. Genellikle Base64 ile kodlanmış bir anahtar olan "SECRET" anahtarının kodunu çözer ve onu "Keys.hmacShaKeyFor" yöntemini kullanarak bir şifreleme anahtarına dönüştürür.
' SECRET ' anahtarı, JWT belirteçlerini imzalamak ve doğrulamak için kullanılan sabit kodlu bir gizli anahtar gibi görünüyor. Bu anahtarın güvenliğini sağlamak ve onu yönetmek için ortam değişkenlerini veya üretim ortamında özel bir gizli yönetim servisini kullanmak gibi daha güvenli yöntemleri dikkate almak önemlidir.
Aşağıdaki gibi User Model Sınıfını oluşturun:
@Entity
@Data
@ToString
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "USERS")
public class UserInfo {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "ID")
private long id;
private String username;
@JsonIgnore
private String password;
@ManyToMany(fetch = FetchType.EAGER)
private Set<UserRole> roles = new HashSet<>();
}UserRepository'yi aşağıdaki gibi oluşturun:
@Repository
public interface UserRepository extends CrudRepository<UserInfo, Long> {
public UserInfo findByUsername(String username);
}UserRole modelini aşağıdaki gibi oluşturun:
@Entity
@Data
@ToString
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "ROLES")
public class UserRole {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "ID")
private long id;
private String name;
}UserDetailsServiceImpl sınıfını oluşturun ve bunu Spring Security tarafından sağlanan UserDetailsService ile uygulayın:
@Component
public class UserDetailsServiceImpl implements UserDetailsService {
@Autowired
private UserRepository userRepository;
private static final Logger logger = LoggerFactory.getLogger(UserDetailsServiceImpl.class);
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
logger.debug("Entering in loadUserByUsername Method...");
UserInfo user = userRepository.findByUsername(username);
if(user == null){
logger.error("Username not found: " + username);
throw new UsernameNotFoundException("could not found user..!!");
}
logger.info("User Authenticated Successfully..!!!");
return new CustomUserDetails(user);
}
}Yukarıdaki kod , bir Spring Boot uygulamasında arayüzü UserDetailsServiceImpluygulayan bir sınıfı tanımlar. Bu sınıf, kullanıcı ayrıntılarının yüklenmesinden ve kimlik doğrulama amacıyla UserDetailsServicebir nesne oluşturulmasından sorumludur . UserDetailsKodu ve işlevselliğini inceleyelim:
loadUserByUsername Yöntem:
- Yöntem , arayüzde tanımlanan yöntemin
loadUserByUsernamebir uygulamasıdır . Bu yöntem, kimlik doğrulama için kullanıcı ayrıntılarını alması gerektiğinde Spring Security tarafından çağrılır.loadUserByUsernameUserDetailsService - Bir kullanıcı oturum açmaya çalıştığında bir kullanıcı adı (veya başka bir benzersiz tanımlayıcı) sağlar. Yöntem
loadUserByUsername, sağlanan bu kullanıcı adına göre kullanıcı deposundaki kullanıcıyı aramaktan sorumludur. - Kullanıcı veritabanında bulunamazsa, yöntem bir hatayı günlüğe kaydeder ve bir
UsernameNotFoundException. Bu istisna, Spring Security'de standart bir istisnadır ve istenen kullanıcının bulunamadığını gösterir. - Kullanıcı bulunursa, yöntem başarılı bir kimlik doğrulama iletisini günlüğe kaydeder ve bir
CustomUserDetailsnesne oluşturur. genellikle kullanıcı adı ve parola gibi kullanıcı bilgilerinin yanı sıra kullanıcı rolleri ve yetkilerini de saran arayüzünCustomUserDetailsözel bir uygulamasıdır .UserDetails - Nesne
UserDetails(bu durumda,CustomUserDetails) yöntem tarafından döndürülür. Bu nesne Spring Security tarafından kimlik doğrulama ve yetkilendirme kontrolleri için kullanılır.
Create CustomUserDetails class:
public class CustomUserDetails extends UserInfo implements UserDetails {
private String username;
private String password;
Collection<? extends GrantedAuthority> authorities;
public CustomUserDetails(UserInfo byUsername) {
this.username = byUsername.getUsername();
this.password= byUsername.getPassword();
List<GrantedAuthority> auths = new ArrayList<>();
for(UserRole role : byUsername.getRoles()){
auths.add(new SimpleGrantedAuthority(role.getName().toUpperCase()));
}
this.authorities = auths;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return authorities;
}
@Override
public String getPassword() {
return password;
}
@Override
public String getUsername() {
return username;
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
}UserDetailsBu sınıf , kimlik doğrulama ve yetkilendirme amacıyla kullanıcı ayrıntılarını ve yetkileri (rolleri) temsil etmek için kullanılan arayüzün özel bir uygulamasıdır .
JwtAuthFilter'ı oluşturun:
@Component
public class JwtAuthFilter extends OncePerRequestFilter {
@Autowired
private JwtService jwtService;
@Autowired
UserDetailsServiceImpl userDetailsServiceImpl;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
String authHeader = request.getHeader("Authorization");
String token = null;
String username = null;
if(authHeader != null && authHeader.startsWith("Bearer ")){
token = authHeader.substring(7);
username = jwtService.extractUsername(token);
}
if(username != null && SecurityContextHolder.getContext().getAuthentication() == null){
UserDetails userDetails = userDetailsServiceImpl.loadUserByUsername(username);
if(jwtService.validateToken(token, userDetails)){
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
}
}
filterChain.doFilter(request, response);
}
}Özel "JwtAuthFilter"ımızda, uygulamamıza yapılan her istek için çağrılan "doFilterInternal" yöntemini geçersiz kıldık. Bu yöntem, bir Bearer tokenunu tanımlamak ve doğrulamak için "Authorization" başlığını inceleyerek gelen istekleri işlemekten sorumludur. İşte nasıl çalışıyor:
1. Filtre, istekte bir "Authorization" başlığı olup olmadığını ve bir Bearer tokenu içerip içermediğini kontrol ederek başlar. Kullanıcı oturum açma işlemiyle ilgili olmayan isteklerin başlıklarında genellikle JWT belirteci bulunmaz, bu nedenle belirteçle ilgili herhangi bir işlem yapılmadan bir sonraki filtre zincirine geçerler.
2. "Authorization" başlığı bulunursa ve bir erişim belirtecinin varlığını belirten "Bearer" ile başlıyorsa, filtre bu belirteci doğrulamaya ve kimlik doğrulamaya devam eder.
3. Erişim belirtecinin başlıktan çıkarılmasıyla başlar.
4. Ardından, sağlanan "JwtService"i kullanarak bu belirteci doğrulayarak bunun geçerli ve süresi dolmamış bir belirteç olduğundan emin olun.
5. Belirteç geçerliyse, filtre bir 'Authentication' nesnesi oluşturarak isteğin kimliğini doğrular. Bu nesne, kullanıcının kimlik doğrulama durumunu temsil eder ve kullanıcı adı ve yetkileri gibi kullanıcı hakkında bilgiler içerir.
6. Kimliği doğrulanan kullanıcı daha sonra "SecurityContext"te saklanır ve uygulamadaki korunan kaynaklara erişime sahip olmaları sağlanır.
Temelde, 'JwtAuthFilter' istekleri durdurur, Bearer tokenlarını arar, bunları doğrular ve token geçerliyse kullanıcıların kimliğini doğrular. Geçerli bir Bearer belirteci olmayan istekler, filter chain boyunca devam ederken, kimliği doğrulanmış kullanıcılar korunan kaynaklara erişim kazanır.
SecurityConfig sınıfını oluşturun:
@Configuration
@EnableWebSecurity
@EnableMethodSecurity
public class SecurityConfig {
@Autowired
JwtAuthFilter jwtAuthFilter;
@Bean
public UserDetailsService userDetailsService() {
return new UserDetailsServiceImpl();
}
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
return http.csrf().disable()
.authorizeHttpRequests()
.requestMatchers("/api/v1/login").permitAll()
.and()
.authorizeHttpRequests().requestMatchers("/api/v1/**")
.authenticated()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authenticationProvider(authenticationProvider())
.addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class).build();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public AuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
authenticationProvider.setUserDetailsService(userDetailsService());
authenticationProvider.setPasswordEncoder(passwordEncoder());
return authenticationProvider;
}
@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration config) throws Exception {
return config.getAuthenticationManager();
}
}Uygulamanın güvenlik ayarlarını, kimlik doğrulamasını ve yetkilendirme kurallarını tanımlar.
securityFilterChain()Bean:
- Bu yöntem, uygulamanın güvenlik filtre zincirini tanımlar. Filtre zinciri çeşitli güvenlik yapılandırmalarını belirtir.
- NET ile Siteler Arası İstek Sahteciliği (CSRF) korumasını devre dışı bırakır
http.csrf().disable(). authorizeHttpRequests()Belirli uç noktalara (örn. "/api/v1/login") genel erişime izin vermek için yetkilendirme kurallarını yapılandırır . Bu uç noktalara yapılan isteklere kimlik doğrulama olmadan izin verilir.- "/api/v1/**" altındaki diğer uç noktalar için kimlik doğrulaması gerekir; bu, kullanıcıların bu kaynaklara erişim için kimlik doğrulamasının yapılması gerektiği anlamına gelir.
SessionCreationPolicy.STATELESSOturum yönetimi , uygulamanın durum bilgisiz olacağını ve oturumların kullanıcı takibi için kullanılmayacağını belirten olarak ayarlanmıştır . Bu, JWT tabanlı kimlik doğrulamada yaygındır.- Muhtemelen .
AuthenticationProvider_DaoAuthenticationProviderBu sağlayıcı, kimlik doğrulama için kullanıcı ayrıntıları servisini ve parola kodlayıcıyı belirtir. JwtAuthFilter'dan öncesini eklerUsernamePasswordAuthenticationFilter. Bu filtre, JWT belirteçlerinin işlenmesinden ve kullanıcıların kimliğinin doğrulanmasından sorumludur.
Şimdi oturum açma API'si için istek yanıtı DTO'larını aşağıdaki gibi oluşturun:
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class AuthRequestDTO {
private String username;
private String password;
}
---------------------------
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class JwtResponseDTO {
private String accessToken;
}Bir AuthController oluşturun:
AuthRequestDTO'yu (kullanıcı adı ve şifre) request body olarak alan ve belirteci oluşturmak için jwtService'i çağıran AuthController'da bir /api/v1/login dinlenme bitiş noktası oluşturacağız.
@PostMapping("/api/v1/login")
public JwtResponseDTO AuthenticateAndGetToken(@RequestBody AuthRequestDTO authRequestDTO){
Authentication authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(authRequestDTO.getUsername(), authRequestDTO.getPassword()));
if(authentication.isAuthenticated()){
return JwtResponseDTO.builder()
.accessToken(jwtService.GenerateToken(authRequestDTO.getUsername()).build();
} else {
throw new UsernameNotFoundException("invalid user request..!!");
}
}@PreAuthorize Ek Açıklamasını Etkinleştir:
Spring Boot uygulamanızda @PreAuthorize ve ayrıca @PostAuthorize ek açıklamalarını etkinleştirmek için öncelikle Global Yöntem Güvenliğini etkinleştirmeniz gerekir. Genel Yöntem Güvenliğini etkinleştirmek için @EnableWebSecurity ek açıklamasını SecurityConfig Java sınıfına ekleyin.
Ek @PreAuthorizeaçıklama yöntem düzeyinde uygulanır. @PreAuthorizeÖrneğin, ek açıklamayı, HTTP isteklerini işleyen , açıklama eklenmiş bir yöntemin üzerine yerleştirebilirsiniz @RequestMapping. Bu, yalnızca ADMIN rolüne sahip kullanıcıların yöntemi çağırmasına olanak tanır.
Ek @PreAuthorizeaçıklama, yöntem güvenlik ifadelerinin kullanılmasına olanak tanır. Açıklamalı bir yöntem içindeki gerçek iş mantığı, @PreAuthorizegüvenlik ifadesi doğrulaması buna izin vermedikçe yürütülmeyecektir. Bunu göstermek için birkaç güvenlik ifadesini inceleyelim.
Rolü()
hasRole() güvenlik ifadesini kullanırken ROLE_ öneki atlanır. Bunun nedeni Spring Framework'ün öneki bizim için otomatik olarak ekleyecektir.
@PreAuthorize("hasRole('ADMIN')")
HasAnyRole()
Birden fazla rolü desteklemeniz gerektiğinde hasAnyRole() ifadesini kullanabilirsiniz.
@PreAuthorize("hasAnyRole('ADMIN',' SUPER_USER')")
Kimlik doğrulama tamamlandığında bir dize döndürecek olan bir ping API'sini api/v1/ping olarak gösterelim . Bu API yalnızca ADMIN rolüne sahip kullanıcı için çalışacaktır, aksi takdirde FORBIDDEN istisnası oluşturulacaktır.
@PreAuthorize("hasAuthority('ADMIN')")
@GetMapping("/ping")
public String test() {
try {
return "Welcome";
} catch (Exception e){
throw new RuntimeException(e);
}
}Demo amaçlı MySQL db kullandım. Application.properties dosyasına aşağıdaki konfigürasyonu koyun.
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/jwt_auth_db
spring.datasource.username=root
spring.datasource.password=root
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=create
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL8Dialect
server.port=9898Kodlamayı neredeyse bitirdik. Şimdi test edelim. Sisteme manuel olarak " username123 " kullanıcı adı ve " test2day " şifresi olan bir kullanıcı ekledim . Kullanıcı kaydı için bir API uç noktası oluşturmadım çünkü öncelikli odak noktam JWT (JSON Web Token) işlevselliğini uygulamaya koymaktı. Bunun yerine kullanıcıyı doğrudan veritabanına ekledim.
Sonuç olarak, artık 60 dakika süreyle geçerli olan bir erişim belirtecinin oluşturulduğunu gösterebiliyorum.

Kimlik doğrulama tamamlandığında bir dize döndürecek olan ping API'sine api/v1/ping olarak basalım .
Aşağıda JWT belirteci bir Bearer belirteci iletilmediği zaman, FORBIDDEN anlamına gelen 403 hata kodunu alıyoruz .

JWT'yi Bearer token olarak aktaralım. İsteğin kimliğinin doğrulandığını ve başarılı yanıtı döndürdüğünü görün.

Sonuç
Umarım Spring Boot 3 ve Spring Security 6 ile JWT Kimlik Doğrulaması ve Yetkilendirmesi hakkında yeterli fikir edinmişsinizdir. GitHub 🐈⬛ veya LinkedIn üzerinden bağlantı kurabiliriz ve geri bildirimlerinizi, önerilerinizi gönderirseniz veya dağıtı sorarsanız çok mutlu abone olun, bana bir e-posta göndermeniz yeterli :) Faydalarını hızlı bir şekilde kayıtlı ve aynı zamanda bir programcı olarak süresini artırmış olursunuz.
Herhangi bir sorunuz veya öneriniz varsa, lütfen yorumlarınızı aşağıya bırakın. Okuduğunuz için teşekkürler!
İyi çalışmalar.