Wallah l'auth elle est censée taffer, mais pt'être y'a un douille, check ça mon reuf 👀
This commit is contained in:
parent
d14ae93f95
commit
c3dd337c7d
@ -3,7 +3,7 @@ package com.guams.review.configuration;
|
||||
import com.guams.review.exception.AlreadyExistsException;
|
||||
import com.guams.review.exception.InvalidNameOrPasswordException;
|
||||
import com.guams.review.exception.NotFoundException;
|
||||
import com.guams.review.exception.UnauthorizedExecption;
|
||||
import com.guams.review.exception.ForbiddenExecption;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.ControllerAdvice;
|
||||
@ -24,11 +24,11 @@ public class Advice {
|
||||
|
||||
@ExceptionHandler(value = InvalidNameOrPasswordException.class)
|
||||
public ResponseEntity<Object> handleInvalidNameOrPassword(InvalidNameOrPasswordException exception) {
|
||||
return new ResponseEntity<>(exception.getMessage(), HttpStatus.UNAUTHORIZED);
|
||||
return new ResponseEntity<>(exception.getMessage(), HttpStatus.FORBIDDEN);
|
||||
}
|
||||
|
||||
@ExceptionHandler(value = UnauthorizedExecption.class)
|
||||
public ResponseEntity<Object> handleUnauthorizedExecption(UnauthorizedExecption exception) {
|
||||
return new ResponseEntity<>(exception.getMessage(), HttpStatus.UNAUTHORIZED);
|
||||
@ExceptionHandler(value = ForbiddenExecption.class)
|
||||
public ResponseEntity<Object> handleUnauthorizedExecption(ForbiddenExecption exception) {
|
||||
return new ResponseEntity<>(exception.getMessage(), HttpStatus.FORBIDDEN);
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
package com.guams.review.configuration;
|
||||
import com.guams.review.model.dao.Author;
|
||||
import com.guams.review.service.AuthorService;
|
||||
import io.jsonwebtoken.JwtException;
|
||||
import jakarta.servlet.FilterChain;
|
||||
|
@ -3,6 +3,7 @@ import com.guams.review.service.AuthorService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
@ -12,6 +13,11 @@ import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
import org.springframework.web.cors.CorsConfigurationSource;
|
||||
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
@Configuration
|
||||
@ -25,15 +31,36 @@ public class SpringSecurityConfig {
|
||||
public SecurityFilterChain securityFilterChain(HttpSecurity http, JwtAuthenticationFilter jwtAuthenticationFilter) throws Exception {
|
||||
return http
|
||||
.csrf(AbstractHttpConfigurer::disable)
|
||||
.cors(cors -> cors.configurationSource(corsConfigurationSource())) // Ajout de la configuration CORS
|
||||
.authorizeHttpRequests(auth -> auth
|
||||
.requestMatchers("/api/authors/login", "/api/authors/register").permitAll()
|
||||
.requestMatchers("/api/authors/me").authenticated() // Autorise les utilisateurs authentifiés
|
||||
.anyRequest().authenticated()
|
||||
.requestMatchers(HttpMethod.GET,
|
||||
"/api/authors",
|
||||
"/api/authors/{id}",
|
||||
"/api/authors/{id}/posts",
|
||||
"/api/posts",
|
||||
"/api/posts/{id}").permitAll() // Autorise les GET sur ces routes
|
||||
.requestMatchers("/api/authors/login", "/api/authors/register").permitAll() // Autorise sans authentification
|
||||
.requestMatchers("/api/authors/me").authenticated() // Requiert authentification
|
||||
.anyRequest().authenticated() // Toutes les autres routes nécessitent une authentification
|
||||
)
|
||||
.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class) // Ajoute le filtre JWT
|
||||
.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public CorsConfigurationSource corsConfigurationSource() {
|
||||
CorsConfiguration configuration = new CorsConfiguration();
|
||||
configuration.setAllowedOrigins(List.of("http://localhost:4200")); // N'autorise que localhost:4200
|
||||
configuration.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE")); // Spécifie les méthodes autorisées
|
||||
configuration.setAllowedHeaders(List.of("Authorization", "Content-Type")); // Limite les en-têtes autorisés
|
||||
configuration.setAllowCredentials(true); // Autorise l'utilisation des cookies ou des tokens
|
||||
configuration.setMaxAge(3600L); // Cache la configuration CORS pendant 1 heure
|
||||
|
||||
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
|
||||
source.registerCorsConfiguration("/**", configuration); // Applique les règles à toutes les routes
|
||||
return source;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public PasswordEncoder passwordEncoder() {
|
||||
return new BCryptPasswordEncoder();
|
||||
|
@ -1,16 +0,0 @@
|
||||
package com.guams.review.configuration;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.config.annotation.CorsRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
@Configuration
|
||||
@EnableWebMvc
|
||||
public class WebConfig implements WebMvcConfigurer {
|
||||
|
||||
@Override
|
||||
public void addCorsMappings(CorsRegistry registry) {
|
||||
registry.addMapping("/**"); // autorise toutes les requêtes externe
|
||||
}
|
||||
}
|
@ -4,13 +4,14 @@ import com.guams.review.configuration.JwtTokenUtil;
|
||||
import com.guams.review.exception.AlreadyExistsException;
|
||||
import com.guams.review.exception.InvalidNameOrPasswordException;
|
||||
import com.guams.review.exception.NotFoundException;
|
||||
import com.guams.review.exception.UnauthorizedExecption;
|
||||
import com.guams.review.exception.ForbiddenExecption;
|
||||
import com.guams.review.model.AuthorRepository;
|
||||
import com.guams.review.model.dao.Author;
|
||||
import com.guams.review.model.dao.AuthorToken;
|
||||
import com.guams.review.model.dao.Post;
|
||||
import com.guams.review.service.AuthorService;
|
||||
import com.guams.review.service.mapper.Mapper;
|
||||
import com.guams.review.service.mapper.AuthorWithToken;
|
||||
import com.guams.review.service.mapper.ReturnableAuthor;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
@ -41,12 +42,12 @@ public class AuthorController {
|
||||
private final Mapper mapper;
|
||||
|
||||
@GetMapping
|
||||
public List<AuthorWithToken> getUsers() {
|
||||
public List<ReturnableAuthor> getUsers() {
|
||||
return authorService.list();
|
||||
}
|
||||
|
||||
@GetMapping("/{id}")
|
||||
public AuthorWithToken findUser(@PathVariable UUID id) {
|
||||
public ReturnableAuthor findUser(@PathVariable UUID id) {
|
||||
Author author = authorService.findById(id).orElseThrow(() -> new NotFoundException("Author not found"));
|
||||
return mapper.mapAuthor(author);
|
||||
}
|
||||
@ -82,14 +83,14 @@ public class AuthorController {
|
||||
}
|
||||
|
||||
@PostMapping("/login")
|
||||
public AuthorWithToken authorLogin(@RequestBody Author author) {
|
||||
public AuthorToken authorLogin(@RequestBody Author author) {
|
||||
try {
|
||||
authenticationManager.authenticate(
|
||||
new UsernamePasswordAuthenticationToken(author.getName(), author.getPassword())
|
||||
);
|
||||
|
||||
String token = jwtTokenUtil.generateToken(author.getName());
|
||||
return mapper.mapAuthor(author).setToken(token);
|
||||
return new AuthorToken().setToken(token);
|
||||
} catch (Exception e) {
|
||||
throw new InvalidNameOrPasswordException(e.getMessage());
|
||||
}
|
||||
@ -105,10 +106,10 @@ public class AuthorController {
|
||||
return new ResponseEntity<>(authorRepository.save(author.setRole("USER")).setPassword(""), HttpStatus.CREATED);
|
||||
}
|
||||
|
||||
@GetMapping("/me")
|
||||
@GetMapping(value = "/me", produces = "application/json")
|
||||
public Author getAuthenticatedUser(Authentication authentication) {
|
||||
if (authentication == null || !authentication.isAuthenticated()) {
|
||||
throw new UnauthorizedExecption("You are not authorized to access this resource");
|
||||
throw new ForbiddenExecption("You are not authorized to access this resource");
|
||||
}
|
||||
|
||||
String username = authentication.getName();
|
||||
@ -120,5 +121,4 @@ public class AuthorController {
|
||||
|
||||
return author.setPassword("");
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,12 +1,17 @@
|
||||
package com.guams.review.controller;
|
||||
|
||||
import com.guams.review.exception.NotFoundException;
|
||||
import com.guams.review.exception.ForbiddenExecption;
|
||||
import com.guams.review.model.AuthorRepository;
|
||||
import com.guams.review.model.dao.Author;
|
||||
import com.guams.review.model.dao.Post;
|
||||
import com.guams.review.service.AuthorService;
|
||||
import com.guams.review.service.PostService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
@ -21,6 +26,8 @@ import java.util.List;
|
||||
public class PostController {
|
||||
|
||||
private final PostService postService;
|
||||
private final AuthorService authorService;
|
||||
private final AuthorRepository authorRepository;
|
||||
|
||||
@GetMapping
|
||||
public List<Post> listPosts() {
|
||||
@ -33,30 +40,59 @@ public class PostController {
|
||||
}
|
||||
|
||||
@PutMapping("/{id}")
|
||||
public void updatePost(@PathVariable Long id, @RequestBody Post updatedPost) {
|
||||
Post postToUpdate = postService.findById(id).orElseThrow(() -> new NotFoundException("Post not found"));
|
||||
postService.insert(updatedPost
|
||||
.setId(postToUpdate.getId())
|
||||
.setIllustration(postToUpdate.getIllustration())
|
||||
.setPublicationDate(postToUpdate.getPublicationDate()));
|
||||
public void updatePost(@PathVariable Long id, @RequestBody Post updatedPost, Authentication authentication) {
|
||||
if (authentication == null) {
|
||||
throw new ForbiddenExecption("You have to login to do that");
|
||||
}
|
||||
Author authenticatedAuthor = authorRepository.findByName(authentication.getName());
|
||||
//Si l'user authent possède ce post
|
||||
if (authorService.listPublicationOfAuthor(authenticatedAuthor.getId()).stream().map(Post::getId).toList().contains(id)) {
|
||||
Post postToUpdate = postService.findById(id).orElseThrow(() -> new NotFoundException("Post not found"));
|
||||
postService.insert(updatedPost
|
||||
.setId(postToUpdate.getId())
|
||||
.setIllustration(postToUpdate.getIllustration())
|
||||
.setPublicationDate(postToUpdate.getPublicationDate()));
|
||||
} else {
|
||||
throw new ForbiddenExecption("You do not have permission to update this post");
|
||||
}
|
||||
}
|
||||
|
||||
@PutMapping(value = "{id}/illustration", consumes = {MediaType.MULTIPART_FORM_DATA_VALUE})
|
||||
public void updateIllustration(@PathVariable Long id, @RequestPart MultipartFile illustration) throws IOException {
|
||||
Post postToUpdate = postService.findById(id).orElseThrow(() -> new NotFoundException("Post not found"));
|
||||
postService.insert(postToUpdate.setIllustration(illustration.getBytes()));
|
||||
public void updateIllustration(@PathVariable Long id, @RequestPart MultipartFile illustration, Authentication authentication) throws IOException {
|
||||
if (authentication == null) {
|
||||
throw new ForbiddenExecption("You have to login to do that");
|
||||
}
|
||||
Author authenticatedAuthor = authorRepository.findByName(authentication.getName());
|
||||
if (authorService.listPublicationOfAuthor(authenticatedAuthor.getId()).stream().map(Post::getId).toList().contains(id)) {
|
||||
Post postToUpdate = postService.findById(id).orElseThrow(() -> new NotFoundException("Post not found"));
|
||||
postService.insert(postToUpdate.setIllustration(illustration.getBytes()));
|
||||
} else {
|
||||
throw new ForbiddenExecption("You do not have permission to update this post");
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public ResponseEntity<Post> addPost(@RequestBody Post postToCreate) {
|
||||
public ResponseEntity<Post> addPost(@RequestBody Post postToCreate, Authentication authentication) {
|
||||
Assert.isNull(postToCreate.getId(), "Post id must be null");
|
||||
if (authentication == null) {
|
||||
throw new ForbiddenExecption("You have to login to do that");
|
||||
}
|
||||
return new ResponseEntity<>(postService.insert(postToCreate.setPublicationDate(LocalDate.now())), HttpStatus.CREATED);
|
||||
}
|
||||
|
||||
@DeleteMapping("{id}")
|
||||
public void deletePost(@PathVariable Long id) {
|
||||
Post postToDelete = postService.findById(id).orElseThrow(() -> new NotFoundException("Post not found"));
|
||||
postService.delete(postToDelete.getId());
|
||||
public void deletePost(@PathVariable Long id, Authentication authentication) {
|
||||
if (authentication == null) {
|
||||
throw new ForbiddenExecption("You have to login to do that");
|
||||
}
|
||||
Author authenticatedAuthor = authorRepository.findByName(authentication.getName());
|
||||
if (authorService.listPublicationOfAuthor(authenticatedAuthor.getId()).stream().map(Post::getId).toList().contains(id)) {
|
||||
Post postToDelete = postService.findById(id).orElseThrow(() -> new NotFoundException("Post not found"));
|
||||
postService.delete(postToDelete.getId());
|
||||
} else {
|
||||
throw new ForbiddenExecption("You do not have permission to delete this post");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,7 @@
|
||||
package com.guams.review.exception;
|
||||
|
||||
public class ForbiddenExecption extends RuntimeException {
|
||||
public ForbiddenExecption(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
package com.guams.review.exception;
|
||||
|
||||
public class UnauthorizedExecption extends RuntimeException {
|
||||
public UnauthorizedExecption(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
12
src/main/java/com/guams/review/model/dao/AuthorToken.java
Normal file
12
src/main/java/com/guams/review/model/dao/AuthorToken.java
Normal file
@ -0,0 +1,12 @@
|
||||
package com.guams.review.model.dao;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@Accessors(chain = true)
|
||||
public class AuthorToken {
|
||||
String token;
|
||||
}
|
@ -1,13 +1,13 @@
|
||||
package com.guams.review.service;
|
||||
|
||||
import com.guams.review.exception.NotFoundException;
|
||||
import com.guams.review.exception.UnauthorizedExecption;
|
||||
import com.guams.review.exception.ForbiddenExecption;
|
||||
import com.guams.review.model.AuthorRepository;
|
||||
import com.guams.review.model.PostRepository;
|
||||
import com.guams.review.model.dao.Author;
|
||||
import com.guams.review.model.dao.Post;
|
||||
import com.guams.review.service.mapper.Mapper;
|
||||
import com.guams.review.service.mapper.AuthorWithToken;
|
||||
import com.guams.review.service.mapper.ReturnableAuthor;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
@ -28,7 +28,7 @@ public class AuthorService implements UserDetailsService
|
||||
private final AuthorRepository authorRepository;
|
||||
private final PostRepository postRepository;
|
||||
|
||||
public List<AuthorWithToken> list() {
|
||||
public List<ReturnableAuthor> list() {
|
||||
return authorRepository.findAll().stream()
|
||||
.map(mapper::mapAuthor)
|
||||
.toList();
|
||||
@ -42,7 +42,7 @@ public class AuthorService implements UserDetailsService
|
||||
return authorRepository.findById(id);
|
||||
}
|
||||
|
||||
public AuthorWithToken insert(Author author) {
|
||||
public ReturnableAuthor insert(Author author) {
|
||||
return mapper.mapAuthor(authorRepository.save(author));
|
||||
}
|
||||
|
||||
@ -58,15 +58,15 @@ public class AuthorService implements UserDetailsService
|
||||
|
||||
public Author verifyIfUserIsAuthorized(Authentication authentication, UUID id) {
|
||||
if (authentication == null || !authentication.isAuthenticated()) {
|
||||
throw new UnauthorizedExecption("You have to login first");
|
||||
throw new ForbiddenExecption("You have to login first");
|
||||
}
|
||||
Author authorToUpdate = findById(id).orElseThrow(() -> new NotFoundException("Author not found"));
|
||||
Author author = findById(id).orElseThrow(() -> new NotFoundException("Author not found"));
|
||||
String username = authentication.getName();
|
||||
Author authorAuthenticated = authorRepository.findByName(username);
|
||||
if (authorAuthenticated.getId() != authorToUpdate.getId() && !authorAuthenticated.getRole().equals("ADMIN")) {
|
||||
throw new UnauthorizedExecption("Specified Author is not authorized to do that");
|
||||
if (authorAuthenticated.getId().compareTo(author.getId()) != 0 && !authorAuthenticated.getRole().equals("ADMIN")) {
|
||||
throw new ForbiddenExecption("Specified Author is not authorized to do that");
|
||||
}
|
||||
return authorToUpdate;
|
||||
return author;
|
||||
}
|
||||
|
||||
public void delete(Author author) {
|
||||
|
@ -8,8 +8,8 @@ public class Mapper {
|
||||
|
||||
public Mapper() {}
|
||||
|
||||
public AuthorWithToken mapAuthor(Author author) {
|
||||
return new AuthorWithToken()
|
||||
public ReturnableAuthor mapAuthor(Author author) {
|
||||
return new ReturnableAuthor()
|
||||
.setId(author.getId())
|
||||
.setName(author.getName())
|
||||
.setRole(author.getRole())
|
||||
|
@ -9,10 +9,9 @@ import java.util.UUID;
|
||||
@Getter
|
||||
@Setter
|
||||
@Accessors(chain = true)
|
||||
public class AuthorWithToken {
|
||||
public class ReturnableAuthor {
|
||||
private UUID id;
|
||||
private String name;
|
||||
private byte[] profilePicture;
|
||||
private String role;
|
||||
private String token;
|
||||
}
|
Loading…
Reference in New Issue
Block a user