From b39307f7d9a14486623e068ec2f17a9819331613 Mon Sep 17 00:00:00 2001 From: Guams Date: Tue, 17 Dec 2024 21:58:04 +0100 Subject: [PATCH] authentification partiellement finie --- pom.xml | 22 +++++++++ .../guams/review/configuration/Advice.java | 12 +++++ .../configuration/SpringSecurityConfig.java | 45 +++++++++++++++++++ .../review/controller/AuthorController.java | 38 +++++++++++++--- .../exception/AlreadyExistsException.java | 7 +++ .../InvalidNameOrPasswordException.java | 7 +++ .../guams/review/model/AuthorRepository.java | 2 + .../com/guams/review/model/dao/Author.java | 3 ++ .../guams/review/service/AuthorService.java | 20 +++++++-- src/main/resources/application.properties | 2 + 10 files changed, 148 insertions(+), 10 deletions(-) create mode 100644 src/main/java/com/guams/review/configuration/SpringSecurityConfig.java create mode 100644 src/main/java/com/guams/review/exception/AlreadyExistsException.java create mode 100644 src/main/java/com/guams/review/exception/InvalidNameOrPasswordException.java diff --git a/pom.xml b/pom.xml index 1e922bd..77cfcd1 100644 --- a/pom.xml +++ b/pom.xml @@ -58,6 +58,28 @@ org.springframework.boot spring-boot-starter-data-jdbc + + org.springframework.boot + spring-boot-starter-oauth2-authorization-server + + + org.springframework.boot + spring-boot-starter-security + + + org.springframework.security + spring-security-test + test + + + org.springframework.boot + spring-boot-devtools + runtime + + + org.springframework.boot + spring-boot-starter-actuator + diff --git a/src/main/java/com/guams/review/configuration/Advice.java b/src/main/java/com/guams/review/configuration/Advice.java index e835bbd..1f398f1 100644 --- a/src/main/java/com/guams/review/configuration/Advice.java +++ b/src/main/java/com/guams/review/configuration/Advice.java @@ -1,5 +1,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 org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -13,4 +15,14 @@ public class Advice { public ResponseEntity handleNotFound(NotFoundException exception) { return new ResponseEntity<>(exception.getMessage(), HttpStatus.NOT_FOUND); } + + @ExceptionHandler(value = AlreadyExistsException.class) + public ResponseEntity handleAlreadyExists(AlreadyExistsException exception) { + return new ResponseEntity<>(exception.getMessage(), HttpStatus.BAD_REQUEST); + } + + @ExceptionHandler(value = InvalidNameOrPasswordException.class) + public ResponseEntity handleInvalidNameOrPassword(InvalidNameOrPasswordException exception) { + return new ResponseEntity<>(exception.getMessage(), HttpStatus.UNAUTHORIZED); + } } diff --git a/src/main/java/com/guams/review/configuration/SpringSecurityConfig.java b/src/main/java/com/guams/review/configuration/SpringSecurityConfig.java new file mode 100644 index 0000000..c50c2bb --- /dev/null +++ b/src/main/java/com/guams/review/configuration/SpringSecurityConfig.java @@ -0,0 +1,45 @@ +package com.guams.review.configuration; + +import com.guams.review.service.AuthorService; +import lombok.RequiredArgsConstructor; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.web.SecurityFilterChain; + + +@Configuration +@EnableWebSecurity +@RequiredArgsConstructor +public class SpringSecurityConfig { + + private final AuthorService authorService; + + @Bean + public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { + return http + .csrf(AbstractHttpConfigurer::disable) + .authorizeHttpRequests(auth -> + auth.requestMatchers("/api/authors/login", "/api/authors/register").permitAll() + .anyRequest().authenticated()).build(); + } + + @Bean + public PasswordEncoder passwordEncoder() { + return new BCryptPasswordEncoder(); + } + + @Bean + public AuthenticationManager authenticationManager(HttpSecurity http, PasswordEncoder passwordEncoder) throws Exception { + AuthenticationManagerBuilder authenticationManagerBuilder = http.getSharedObject(AuthenticationManagerBuilder.class); + authenticationManagerBuilder.userDetailsService(authorService).passwordEncoder(passwordEncoder); + return authenticationManagerBuilder.build(); + } + +} diff --git a/src/main/java/com/guams/review/controller/AuthorController.java b/src/main/java/com/guams/review/controller/AuthorController.java index b8711b4..b6f3c66 100644 --- a/src/main/java/com/guams/review/controller/AuthorController.java +++ b/src/main/java/com/guams/review/controller/AuthorController.java @@ -1,13 +1,21 @@ package com.guams.review.controller; +import com.guams.review.exception.AlreadyExistsException; +import com.guams.review.exception.InvalidNameOrPasswordException; import com.guams.review.exception.NotFoundException; +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.mapper.Mapper; import com.guams.review.service.mapper.ReturnableAuthor; import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.util.Assert; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; @@ -21,7 +29,11 @@ import java.util.UUID; @RequiredArgsConstructor public class AuthorController { + + private final PasswordEncoder passwordEncoder; + private final AuthenticationManager authenticationManager; private final AuthorService authorService; + private final AuthorRepository authorRepository; private final Mapper mapper; @GetMapping @@ -35,12 +47,6 @@ public class AuthorController { return mapper.mapAuthor(author); } - @PostMapping - public ReturnableAuthor addUser(@RequestBody Author author) { - Assert.isNull(author.getId(), "Author id must be null"); - return authorService.insert(author); - } - @PutMapping("/{id}") public void updateUser(@PathVariable UUID id, @RequestBody Author updatedAuthor) { Author authorToUpdate = authorService.findById(id).orElseThrow(() -> new NotFoundException("Author not found")); @@ -70,4 +76,24 @@ public class AuthorController { Author author = authorService.findById(id).orElseThrow(() -> new NotFoundException("Author not found")); return authorService.listPublicationOfAuthor(author.getId()); } + + @PostMapping("/login") + public void authorLogin(@RequestBody Author author) { + try { + authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(author.getName(), author.getPassword())); + } + catch (Exception e) { + throw new InvalidNameOrPasswordException(e.getMessage()); + } + } + + @PostMapping("/register") + public ResponseEntity authorRegister(@RequestBody Author author) { + Assert.isNull(author.getId(), "Author id must be null"); + if (authorRepository.findByName(author.getName()) != null) { + throw new AlreadyExistsException("Author already exists"); + } + author.setPassword(passwordEncoder.encode(author.getPassword())); + return new ResponseEntity<>(authorRepository.save(author).setPassword(""), HttpStatus.CREATED); + } } diff --git a/src/main/java/com/guams/review/exception/AlreadyExistsException.java b/src/main/java/com/guams/review/exception/AlreadyExistsException.java new file mode 100644 index 0000000..b2958a4 --- /dev/null +++ b/src/main/java/com/guams/review/exception/AlreadyExistsException.java @@ -0,0 +1,7 @@ +package com.guams.review.exception; + +public class AlreadyExistsException extends RuntimeException { + public AlreadyExistsException(String message) { + super(message); + } +} diff --git a/src/main/java/com/guams/review/exception/InvalidNameOrPasswordException.java b/src/main/java/com/guams/review/exception/InvalidNameOrPasswordException.java new file mode 100644 index 0000000..c7c56b8 --- /dev/null +++ b/src/main/java/com/guams/review/exception/InvalidNameOrPasswordException.java @@ -0,0 +1,7 @@ +package com.guams.review.exception; + +public class InvalidNameOrPasswordException extends RuntimeException { + public InvalidNameOrPasswordException(String message) { + super(message); + } +} diff --git a/src/main/java/com/guams/review/model/AuthorRepository.java b/src/main/java/com/guams/review/model/AuthorRepository.java index feac87f..607d6f3 100644 --- a/src/main/java/com/guams/review/model/AuthorRepository.java +++ b/src/main/java/com/guams/review/model/AuthorRepository.java @@ -21,4 +21,6 @@ public interface AuthorRepository extends CrudRepository { void deletePublication(UUID authorId, Long postId); List findAll(); + + Author findByName(String name); } diff --git a/src/main/java/com/guams/review/model/dao/Author.java b/src/main/java/com/guams/review/model/dao/Author.java index 9ea00ce..621241e 100644 --- a/src/main/java/com/guams/review/model/dao/Author.java +++ b/src/main/java/com/guams/review/model/dao/Author.java @@ -26,6 +26,9 @@ public class Author { @Column("password") String password; +// @Column("role") +// String role; + @Column("profile_picture") byte[] profilePicture; } \ No newline at end of file diff --git a/src/main/java/com/guams/review/service/AuthorService.java b/src/main/java/com/guams/review/service/AuthorService.java index bf1e8b9..fef014e 100644 --- a/src/main/java/com/guams/review/service/AuthorService.java +++ b/src/main/java/com/guams/review/service/AuthorService.java @@ -7,16 +7,19 @@ import com.guams.review.model.dao.Post; import com.guams.review.service.mapper.Mapper; import com.guams.review.service.mapper.ReturnableAuthor; import lombok.RequiredArgsConstructor; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.userdetails.User; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.List; -import java.util.Optional; -import java.util.UUID; +import java.util.*; @Service @RequiredArgsConstructor -public class AuthorService +public class AuthorService implements UserDetailsService { private final Mapper mapper; private final AuthorRepository authorRepository; @@ -53,4 +56,13 @@ public class AuthorService public void delete(Author author) { authorRepository.delete(author); } + + @Override + public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { + Author author = authorRepository.findByName(username); + if (author == null) { + throw new UsernameNotFoundException(username); + } + return new User(author.getName(), author.getPassword(), Collections.singletonList(new SimpleGrantedAuthority("USER"))); // temporaire pour le role + } } diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index d6d3e00..69d116f 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1,3 +1,5 @@ +spring.security.oauth2.client.registration.github.client-id=Ov23ligoCzKHHyyIzIbS +spring.security.oauth2.client.registration.github.client-secret=c660f476763404f41da43e7a3f7e9648f94b107d spring.application.name=reView spring.datasource.url=jdbc:postgresql://localhost:5432/reviewDB spring.datasource.username=postgres