Implement token blacklist for JWT logout support

- TokenBlacklistService tracks invalidated tokens using Caffeine cache.
- AuthController adds tokens to blacklist on logout.
- JwtAuthenticationFilter blocks blacklisted tokens during authentication.
This commit is contained in:
K
2025-07-03 02:57:29 +05:30
parent dd52421392
commit 218ccb720f
3 changed files with 56 additions and 4 deletions
@@ -4,6 +4,9 @@ import com.skycrate.backend.skycrateBackend.dto.LoginRequest;
import com.skycrate.backend.skycrateBackend.security.JwtService;
import com.skycrate.backend.skycrateBackend.entity.User;
import com.skycrate.backend.skycrateBackend.repository.UserRepository;
import com.skycrate.backend.skycrateBackend.security.TokenBlacklistService;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
@@ -48,9 +51,19 @@ public class AuthController {
return ResponseEntity.ok().body(token);
}
@Autowired
private TokenBlacklistService tokenBlacklistService;
@PostMapping("/logout")
public ResponseEntity<?> logout() {
// Client-side token deletion (or implement blacklist)
return ResponseEntity.ok("Logged out (client should delete token)");
public ResponseEntity<?> logout(HttpServletRequest request) {
String authHeader = request.getHeader("Authorization");
if (authHeader == null || !authHeader.startsWith("Bearer ")) {
return ResponseEntity.badRequest().body("Missing or invalid Authorization header");
}
String token = authHeader.substring(7);
tokenBlacklistService.blacklistToken(token);
return ResponseEntity.ok("Logged out successfully");
}
}
@@ -20,10 +20,14 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter {
private final JwtService jwtService;
private final UserRepository userRepository;
private final TokenBlacklistService tokenBlacklistService;
public JwtAuthenticationFilter(JwtService jwtService, UserRepository userRepository) {
public JwtAuthenticationFilter(JwtService jwtService,
UserRepository userRepository,
TokenBlacklistService tokenBlacklistService) {
this.jwtService = jwtService;
this.userRepository = userRepository;
this.tokenBlacklistService = tokenBlacklistService;
}
@Override
@@ -42,6 +46,14 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter {
}
jwt = authHeader.substring(7);
// Check if token is blacklisted
if (tokenBlacklistService.isTokenBlacklisted(jwt)) {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.getWriter().write("Token has been blacklisted");
return;
}
try {
userEmail = jwtService.extractUsername(jwt);
} catch (Exception e) {
@@ -0,0 +1,27 @@
package com.skycrate.backend.skycrateBackend.security;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import org.springframework.stereotype.Service;
import java.util.concurrent.TimeUnit;
@Service
public class TokenBlacklistService {
private final Cache<String, Boolean> blacklistCache;
public TokenBlacklistService() {
this.blacklistCache = Caffeine.newBuilder()
.expireAfterWrite(1, TimeUnit.HOURS)
.build();
}
public void blacklistToken(String token) {
blacklistCache.put(token, true);
}
public boolean isTokenBlacklisted(String token) {
return blacklistCache.getIfPresent(token) != null;
}
}