Refactor Auth and HDFS controllers, fix User model, and improve HDFS config
- Rewrote AuthController to inject all dependencies via constructor - Fixed token refresh/login logic and added rate limiter and blacklist support - Implemented getters in LoginRequest DTO - Updated User model to implement UserDetails and extend entity.User - Switched HDFScontroller to use entity.User instead of models.User - Rewrote HDFSConfig to include static getHDFS() method and secure config via env vars - Simplified JwtService, added overload for entity.User, and fixed key handling
This commit is contained in:
@@ -8,13 +8,35 @@ import org.springframework.context.annotation.Bean;
|
|||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.security.PrivilegedExceptionAction;
|
import java.security.PrivilegedExceptionAction;
|
||||||
|
|
||||||
|
// HDFS configuration bean to securely connect to a remote Hadoop cluster.
|
||||||
|
@Configuration
|
||||||
public class HDFSConfig {
|
public class HDFSConfig {
|
||||||
public static FileSystem getHDFS() throws Exception {
|
|
||||||
Configuration conf = new Configuration();
|
private static final String HDFS_URI = System.getenv("HDFS_URI"); // export HDFS_URI=hdfs://192.168.29.30:9000
|
||||||
conf.set("fs.defaultFS", "hdfs://namenode:9000");
|
private static final String HDFS_USER = System.getenv("HDFS_USER"); // Hadoop user (if needed)
|
||||||
return FileSystem.get(new URI("hdfs://namenode:9000"), conf);
|
|
||||||
|
// Configures and returns a secured HDFS FileSystem instance.
|
||||||
|
@Bean
|
||||||
|
public FileSystem fileSystem() throws Exception {
|
||||||
|
return getHDFS(); // use the static method internally
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Static method to get a FileSystem instance. Used by other classes like HDFSController.
|
||||||
|
public static FileSystem getHDFS() throws Exception {
|
||||||
|
if (HDFS_URI == null || HDFS_URI.isBlank()) {
|
||||||
|
throw new IllegalStateException("HDFS_URI environment variable not set.");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
Configuration conf = new Configuration();
|
||||||
|
conf.set("fs.defaultFS", HDFS_URI);
|
||||||
|
|
||||||
|
if (HDFS_USER != null && !HDFS_USER.isBlank()) {
|
||||||
|
return UserGroupInformation.createRemoteUser(HDFS_USER)
|
||||||
|
.doAs((PrivilegedExceptionAction<FileSystem>) () ->
|
||||||
|
FileSystem.get(new URI(HDFS_URI), conf)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return FileSystem.get(new URI(HDFS_URI), conf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,13 +1,17 @@
|
|||||||
package com.skycrate.backend.skycrateBackend.controller;
|
package com.skycrate.backend.skycrateBackend.controller;
|
||||||
|
|
||||||
import com.skycrate.backend.skycrateBackend.dto.LoginRequest;
|
import com.skycrate.backend.skycrateBackend.dto.LoginRequest;
|
||||||
import com.skycrate.backend.skycrateBackend.services.JwtService;
|
import com.skycrate.backend.skycrateBackend.dto.LoginResponse;
|
||||||
|
import com.skycrate.backend.skycrateBackend.dto.TokenRefreshRequest;
|
||||||
|
import com.skycrate.backend.skycrateBackend.dto.TokenRefreshResponse;
|
||||||
|
import com.skycrate.backend.skycrateBackend.entity.RefreshToken;
|
||||||
import com.skycrate.backend.skycrateBackend.entity.User;
|
import com.skycrate.backend.skycrateBackend.entity.User;
|
||||||
import com.skycrate.backend.skycrateBackend.repository.UserRepository;
|
import com.skycrate.backend.skycrateBackend.repository.UserRepository;
|
||||||
import com.skycrate.backend.skycrateBackend.security.TokenBlacklistService;
|
import com.skycrate.backend.skycrateBackend.security.TokenBlacklistService;
|
||||||
|
import com.skycrate.backend.skycrateBackend.services.JwtService;
|
||||||
import com.skycrate.backend.skycrateBackend.services.RefreshTokenService;
|
import com.skycrate.backend.skycrateBackend.services.RefreshTokenService;
|
||||||
|
import com.skycrate.backend.skycrateBackend.services.RateLimiterService;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.security.authentication.AuthenticationManager;
|
import org.springframework.security.authentication.AuthenticationManager;
|
||||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||||
@@ -20,16 +24,26 @@ public class AuthController {
|
|||||||
private final AuthenticationManager authManager;
|
private final AuthenticationManager authManager;
|
||||||
private final JwtService jwtService;
|
private final JwtService jwtService;
|
||||||
private final UserRepository userRepository;
|
private final UserRepository userRepository;
|
||||||
|
private final RefreshTokenService refreshTokenService;
|
||||||
|
private final TokenBlacklistService tokenBlacklistService;
|
||||||
|
private final RateLimiterService rateLimiterService;
|
||||||
|
|
||||||
public AuthController(AuthenticationManager authManager, JwtService jwtService, UserRepository userRepository) {
|
public AuthController(
|
||||||
|
AuthenticationManager authManager,
|
||||||
|
JwtService jwtService,
|
||||||
|
UserRepository userRepository,
|
||||||
|
RefreshTokenService refreshTokenService,
|
||||||
|
TokenBlacklistService tokenBlacklistService,
|
||||||
|
RateLimiterService rateLimiterService
|
||||||
|
) {
|
||||||
this.authManager = authManager;
|
this.authManager = authManager;
|
||||||
this.jwtService = jwtService;
|
this.jwtService = jwtService;
|
||||||
this.userRepository = userRepository;
|
this.userRepository = userRepository;
|
||||||
|
this.refreshTokenService = refreshTokenService;
|
||||||
|
this.tokenBlacklistService = tokenBlacklistService;
|
||||||
|
this.rateLimiterService = rateLimiterService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private RefreshTokenService refreshTokenService;
|
|
||||||
|
|
||||||
@PostMapping("/login")
|
@PostMapping("/login")
|
||||||
public ResponseEntity<?> login(@RequestBody LoginRequest request, HttpServletRequest servletRequest) {
|
public ResponseEntity<?> login(@RequestBody LoginRequest request, HttpServletRequest servletRequest) {
|
||||||
String ip = servletRequest.getRemoteAddr();
|
String ip = servletRequest.getRemoteAddr();
|
||||||
@@ -52,43 +66,29 @@ public class AuthController {
|
|||||||
|
|
||||||
rateLimiterService.resetAttempts(ip);
|
rateLimiterService.resetAttempts(ip);
|
||||||
|
|
||||||
// ✅ Generate tokens
|
|
||||||
String accessToken = jwtService.generateToken(user);
|
String accessToken = jwtService.generateToken(user);
|
||||||
RefreshToken refreshToken = refreshTokenService.createRefreshToken(user);
|
RefreshToken refreshToken = refreshTokenService.createRefreshToken(user);
|
||||||
|
|
||||||
return ResponseEntity.ok(new LoginResponse(accessToken, refreshToken.getToken()));
|
return ResponseEntity.ok(new LoginResponse(accessToken, refreshToken.getToken()));
|
||||||
}
|
}
|
||||||
|
|
||||||
User user = userRepository.findByEmail(request.getEmail())
|
@PostMapping("/logout")
|
||||||
.orElseThrow(() -> new RuntimeException("User not found"));
|
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");
|
||||||
|
}
|
||||||
|
|
||||||
rateLimiterService.resetAttempts(ip);
|
String token = authHeader.substring(7);
|
||||||
String token = jwtService.generateToken(user);
|
|
||||||
return ResponseEntity.ok().body(token);
|
tokenBlacklistService.blacklistToken(token);
|
||||||
|
|
||||||
|
String email = jwtService.extractUsername(token);
|
||||||
|
userRepository.findByEmail(email).ifPresent(refreshTokenService::deleteByUser);
|
||||||
|
|
||||||
|
return ResponseEntity.ok("Logged out successfully");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private TokenBlacklistService tokenBlacklistService;
|
|
||||||
|
|
||||||
@PostMapping("/logout")
|
|
||||||
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);
|
|
||||||
|
|
||||||
// Blacklist access token
|
|
||||||
tokenBlacklistService.blacklistToken(token);
|
|
||||||
|
|
||||||
// Extract user from token and delete their refresh token
|
|
||||||
String email = jwtService.extractUsername(token);
|
|
||||||
userRepository.findByEmail(email).ifPresent(refreshTokenService::deleteByUser);
|
|
||||||
|
|
||||||
return ResponseEntity.ok("Logged out successfully");
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping("/refresh")
|
@PostMapping("/refresh")
|
||||||
public ResponseEntity<?> refresh(@RequestBody TokenRefreshRequest request) {
|
public ResponseEntity<?> refresh(@RequestBody TokenRefreshRequest request) {
|
||||||
String requestToken = request.getRefreshToken();
|
String requestToken = request.getRefreshToken();
|
||||||
@@ -105,5 +105,4 @@ public ResponseEntity<?> logout(HttpServletRequest request) {
|
|||||||
})
|
})
|
||||||
.orElseGet(() -> ResponseEntity.status(403).body("Invalid refresh token"));
|
.orElseGet(() -> ResponseEntity.status(403).body("Invalid refresh token"));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -2,9 +2,8 @@ package com.skycrate.backend.skycrateBackend.controller;
|
|||||||
|
|
||||||
import com.skycrate.backend.skycrateBackend.config.HDFSConfig;
|
import com.skycrate.backend.skycrateBackend.config.HDFSConfig;
|
||||||
import com.skycrate.backend.skycrateBackend.dto.ResponseDTO;
|
import com.skycrate.backend.skycrateBackend.dto.ResponseDTO;
|
||||||
import com.skycrate.backend.skycrateBackend.models.User;
|
import com.skycrate.backend.skycrateBackend.entity.User;
|
||||||
import com.skycrate.backend.skycrateBackend.repository.UserRepository;
|
import com.skycrate.backend.skycrateBackend.repository.UserRepository;
|
||||||
import com.skycrate.backend.skycrateBackend.services.EncryptionUtil;
|
|
||||||
import com.skycrate.backend.skycrateBackend.services.HDFSOperations;
|
import com.skycrate.backend.skycrateBackend.services.HDFSOperations;
|
||||||
import com.skycrate.backend.skycrateBackend.utils.KeyUtil;
|
import com.skycrate.backend.skycrateBackend.utils.KeyUtil;
|
||||||
import com.skycrate.backend.skycrateBackend.utils.RSAKeyUtil;
|
import com.skycrate.backend.skycrateBackend.utils.RSAKeyUtil;
|
||||||
@@ -36,9 +35,6 @@ import javax.crypto.SecretKey;
|
|||||||
import javax.crypto.spec.SecretKeySpec;
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
import java.io.File; // For java.io.File
|
import java.io.File; // For java.io.File
|
||||||
|
|
||||||
import static com.skycrate.backend.skycrateBackend.utils.KeyUtil.getPrivateKeyForUser;
|
|
||||||
import static com.skycrate.backend.skycrateBackend.utils.KeyUtil.getPublicKeyForUser;
|
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/hdfs")
|
@RequestMapping("/api/hdfs")
|
||||||
public class HDFScontroller {
|
public class HDFScontroller {
|
||||||
|
|||||||
@@ -5,4 +5,9 @@ public class LoginRequest {
|
|||||||
private String password;
|
private String password;
|
||||||
|
|
||||||
// Getters and setters
|
// Getters and setters
|
||||||
}
|
public String getEmail() { return email; }
|
||||||
|
public void setEmail(String email) { this.email = email; }
|
||||||
|
|
||||||
|
public String getPassword() { return password; }
|
||||||
|
public void setPassword(String password) { this.password = password; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
package com.skycrate.backend.skycrateBackend.entity;
|
||||||
|
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
import lombok.*;
|
||||||
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "users")
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
@Builder
|
||||||
|
public class User implements UserDetails {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Column(nullable = false, unique = true)
|
||||||
|
private String email;
|
||||||
|
|
||||||
|
@Column(nullable = false)
|
||||||
|
private String password;
|
||||||
|
|
||||||
|
@Column(nullable = false, unique = true)
|
||||||
|
private String username;
|
||||||
|
|
||||||
|
@Column(nullable = false)
|
||||||
|
private String fullname;
|
||||||
|
|
||||||
|
@Lob
|
||||||
|
private byte[] publicKey;
|
||||||
|
|
||||||
|
@Lob
|
||||||
|
private byte[] privateKey;
|
||||||
|
|
||||||
|
// --- UserDetails interface methods ---
|
||||||
|
@Override
|
||||||
|
public Collection<? extends GrantedAuthority> getAuthorities() {
|
||||||
|
return List.of(); // Add roles/authorities if needed
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getUsername() {
|
||||||
|
return email; // or return username if that's your login key
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPassword() {
|
||||||
|
return this.password;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAccountNonExpired() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAccountNonLocked() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isCredentialsNonExpired() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEnabled() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Extra getter methods for HDFScontroller compatibility ---
|
||||||
|
public byte[] getPublicKey() {
|
||||||
|
return publicKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getPrivateKey() {
|
||||||
|
return privateKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFullname() {
|
||||||
|
return fullname;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
package com.skycrate.backend.skycrateBackend.models;
|
package com.skycrate.backend.skycrateBackend.models;
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -13,7 +12,7 @@ import jakarta.persistence.*;
|
|||||||
|
|
||||||
@Table(name = "users")
|
@Table(name = "users")
|
||||||
@Entity
|
@Entity
|
||||||
public class User implements UserDetails {
|
public class User extends com.skycrate.backend.skycrateBackend.entity.User implements UserDetails {
|
||||||
|
|
||||||
@Id
|
@Id
|
||||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
|||||||
@@ -1,83 +1,66 @@
|
|||||||
package com.skycrate.backend.skycrateBackend.services;
|
package com.skycrate.backend.skycrateBackend.services;
|
||||||
|
|
||||||
import java.security.Key;
|
import com.skycrate.backend.skycrateBackend.entity.User;
|
||||||
import java.util.Date;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.function.Function;
|
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
|
||||||
import org.springframework.security.core.userdetails.UserDetails;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
|
|
||||||
import io.jsonwebtoken.Claims;
|
import io.jsonwebtoken.Claims;
|
||||||
import io.jsonwebtoken.Jwts;
|
import io.jsonwebtoken.Jwts;
|
||||||
import io.jsonwebtoken.SignatureAlgorithm;
|
import io.jsonwebtoken.SignatureAlgorithm;
|
||||||
import io.jsonwebtoken.io.Decoders;
|
|
||||||
import io.jsonwebtoken.security.Keys;
|
import io.jsonwebtoken.security.Keys;
|
||||||
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.security.Key;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class JwtService {
|
public class JwtService {
|
||||||
@Value("${security.jwt.secret-key}")
|
|
||||||
private String secretKey;
|
|
||||||
|
|
||||||
@Value("${security.jwt.expiration-time}")
|
|
||||||
private long jwtExpiration;
|
|
||||||
|
|
||||||
public String extractUsername(String token){
|
// Recommend moving this key to environment variable or config file
|
||||||
return extractClaim(token,Claims::getSubject);
|
private static final String SECRET_KEY = "your-256-bit-secret-your-256-bit-secret"; // must be 256-bit
|
||||||
|
|
||||||
|
private final long EXPIRATION_TIME = 1000 * 60 * 15; // 15 minutes
|
||||||
|
|
||||||
|
private Key getSigningKey() {
|
||||||
|
return Keys.hmacShaKeyFor(SECRET_KEY.getBytes());
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T> T extractClaim(String token,Function<Claims,T> claimsResolver){
|
public String extractUsername(String token) {
|
||||||
final Claims claims=extractAllClaims(token);
|
return extractClaim(token, Claims::getSubject);
|
||||||
return claimsResolver.apply(claims);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String generateToken(UserDetails userDetails) {
|
public Date extractExpiration(String token) {
|
||||||
return generateToken(new HashMap<>(), userDetails);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String generateToken(Map<String, Object> extraClaims, UserDetails userDetails) {
|
|
||||||
return buildToken(extraClaims, userDetails, jwtExpiration);
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getExpirtationTime(){
|
|
||||||
return jwtExpiration;
|
|
||||||
}
|
|
||||||
private String buildToken(Map<String,Object> extraClaims,UserDetails userDetails,long expiration){
|
|
||||||
|
|
||||||
return Jwts.builder().setClaims(extraClaims).setSubject(userDetails.getUsername())
|
|
||||||
.setIssuedAt(new Date(System.currentTimeMillis()))
|
|
||||||
.setExpiration(new Date(System.currentTimeMillis() + expiration))
|
|
||||||
.signWith(getSignInKey(), SignatureAlgorithm.HS256)
|
|
||||||
.compact();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isTokenValid(String token, UserDetails userDetails) {
|
|
||||||
final String username = extractUsername(token);
|
|
||||||
return (username.equals(userDetails.getUsername())) && !isTokenExpired(token);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isTokenExpired(String token) {
|
|
||||||
return extractExpiration(token).before(new Date());
|
|
||||||
}
|
|
||||||
|
|
||||||
private Date extractExpiration(String token) {
|
|
||||||
return extractClaim(token, Claims::getExpiration);
|
return extractClaim(token, Claims::getExpiration);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Claims extractAllClaims(String token) {
|
public <T> T extractClaim(String token, Function<Claims, T> claimsResolver) {
|
||||||
return Jwts
|
Claims claims = Jwts.parserBuilder()
|
||||||
.parserBuilder()
|
.setSigningKey(getSigningKey())
|
||||||
.setSigningKey(getSignInKey())
|
|
||||||
.build()
|
.build()
|
||||||
.parseClaimsJws(token)
|
.parseClaimsJws(token)
|
||||||
.getBody();
|
.getBody();
|
||||||
|
return claimsResolver.apply(claims);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Key getSignInKey() {
|
public boolean isTokenValid(String token, UserDetails userDetails) {
|
||||||
byte[] keyBytes = Decoders.BASE64.decode(secretKey);
|
final String username = extractUsername(token);
|
||||||
return Keys.hmacShaKeyFor(keyBytes);
|
return (username.equals(userDetails.getUsername()) && !isTokenExpired(token));
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isTokenExpired(String token) {
|
||||||
|
return extractExpiration(token).before(new Date());
|
||||||
|
}
|
||||||
|
|
||||||
|
public String generateToken(UserDetails userDetails) {
|
||||||
|
return Jwts.builder()
|
||||||
|
.setSubject(userDetails.getUsername())
|
||||||
|
.setIssuedAt(new Date())
|
||||||
|
.setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME))
|
||||||
|
.signWith(getSigningKey(), SignatureAlgorithm.HS256)
|
||||||
|
.compact();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overload for your entity
|
||||||
|
public String generateToken(User user) {
|
||||||
|
return generateToken((UserDetails) user);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
// NEED TO IMPLEMENT SAHI SE
|
||||||
|
package com.skycrate.backend.skycrateBackend.services;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class RateLimiterService {
|
||||||
|
private final ConcurrentHashMap<String, Integer> attempts = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
public boolean isBlocked(String ip) {
|
||||||
|
return attempts.getOrDefault(ip, 0) >= 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void recordFailedAttempt(String ip) {
|
||||||
|
attempts.put(ip, attempts.getOrDefault(ip, 0) + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void resetAttempts(String ip) {
|
||||||
|
attempts.remove(ip);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user