comment delete et limite de 5 requete post toute les minutes

This commit is contained in:
Guams 2025-01-24 20:53:41 +01:00
parent f41c830970
commit 40da59bd31
4 changed files with 71 additions and 4 deletions

View File

@ -1,4 +1,5 @@
package com.guams.review.configuration;
import com.guams.review.service.AuthorService;
import io.jsonwebtoken.JwtException;
import jakarta.servlet.FilterChain;
@ -11,7 +12,11 @@ import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import java.io.IOException;
import java.time.Instant;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {
@ -19,6 +24,13 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter {
private final JwtTokenUtil jwtTokenUtil;
private final AuthorService authorService;
// Map pour traquer les requêtes : UUID -> { dernière réinitialisation, compteur de requêtes }
private final ConcurrentHashMap<String, RateLimiter> rateLimiters = new ConcurrentHashMap<>();
// Configuration du rate limiting
private static final int MAX_REQUESTS = 5;
private static final long TIME_WINDOW_MS = 60 * 1000; // 1 minute
public JwtAuthenticationFilter(JwtTokenUtil jwtTokenUtil, AuthorService authorService) {
this.jwtTokenUtil = jwtTokenUtil;
this.authorService = authorService;
@ -35,9 +47,16 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter {
String authorUuid = jwtTokenUtil.extractAuthorId(token); // Récupère l'UUID du token
if (authorUuid != null && SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails = authorService.loadUserByUsername(authorUuid); // Utilise le service pour charger l'auteur par UUID
UserDetails userDetails = authorService.loadUserByUsername(authorUuid); // Charge l'auteur
if (jwtTokenUtil.validateToken(token, userDetails, authorUuid)) {
// Applique le rate limiting
if (isRateLimited(authorUuid, request)) {
response.setStatus(429); // TOO MANY REQUESTS
response.getWriter().write("Rate limit exceeded. Please try again later.");
return;
}
UsernamePasswordAuthenticationToken authentication =
new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
@ -50,7 +69,42 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter {
}
}
filterChain.doFilter(request, response); // Continue le traitement
}
private boolean isRateLimited(String authorUuid, HttpServletRequest request) {
// Ne limite que les requêtes POST
if (!"POST".equalsIgnoreCase(request.getMethod())) {
return false;
}
// Récupère ou crée un RateLimiter pour l'utilisateur
RateLimiter limiter = rateLimiters.computeIfAbsent(authorUuid, k -> new RateLimiter());
synchronized (limiter) {
long now = Instant.now().toEpochMilli();
if (now - limiter.lastReset > TIME_WINDOW_MS) {
// Réinitialise la fenêtre de temps et le compteur
limiter.lastReset = now;
limiter.requestCount.set(0);
}
if (limiter.requestCount.incrementAndGet() > MAX_REQUESTS) {
return true; // Limite atteinte
}
}
return false;
}
// Classe interne pour suivre les requêtes
private static class RateLimiter {
private long lastReset;
private AtomicInteger requestCount;
public RateLimiter() {
this.lastReset = Instant.now().toEpochMilli();
this.requestCount = new AtomicInteger(0);
}
}
}

View File

@ -64,6 +64,12 @@ public class AuthorController {
}
}
// @PutMapping("/{id}/password")
// public void changePassword(@PathVariable UUID id, @RequestBody Author updatedAuthor, Authentication authentication) {
// Author authorToUpdate = authorService.verifyIfUserIsAuthorized(authentication, id);
// if (passwordEncoder.matches(updatedAuthor.getPassword(), authorToUpdate.getPassword())) {}
// }
@PutMapping(value = "{id}/avatar", consumes = {MediaType.MULTIPART_FORM_DATA_VALUE})
public Author updateUserAvatar(@PathVariable UUID id, @RequestPart MultipartFile avatar, Authentication authentication) throws IOException {
Author authorToUpdate = authorService.verifyIfUserIsAuthorized(authentication, id);

View File

@ -85,7 +85,7 @@ public class CommentController {
throw new UnauthorizedExecption("You are not authorized to access this resource");
}
Comment commentToDelete = commentService.findById(id).orElseThrow(() -> new NotFoundException("Comment not found"));
commentService.delete(commentToDelete);
commentService.deleteAssociationByCommentId(commentToDelete.getId());
commentService.delete(commentToDelete);
}
}

View File

@ -107,7 +107,14 @@ public class PostController {
Author authenticatedAuthor = authorService.findByName(authentication.getName()).orElseThrow(() -> new NotFoundException("Author not found"));
if (authorService.listPublicationOfAuthor(authenticatedAuthor.getId()).stream().map(Post::getId).toList().contains(id)) {
Post postToDelete = postService.findById(id).orElseThrow(() -> new NotFoundException("Post not found"));
commentService.getCommentsByPostId(id).stream().map(mapper::mapCommentWithAuthor).forEach(commentService::delete);
commentService.getCommentsByPostId(id)
.stream()
.map(mapper::mapCommentWithAuthor)
.forEach(comment -> commentService.deleteAssociationByCommentId(comment.getId()));
commentService.getCommentsByPostId(id)
.stream()
.map(mapper::mapCommentWithAuthor)
.forEach(commentService::delete);
postService.delete(authenticatedAuthor.getId(), postToDelete.getId());
} else {
throw new UnauthorizedExecption("You do not have permission to delete this post");