From dd1fdae060f6e59eb063d39fdd9c3c0e169b653c Mon Sep 17 00:00:00 2001 From: "ityurner02@mail.ru" Date: Sun, 28 May 2023 20:24:04 +0400 Subject: [PATCH] =?UTF-8?q?=D0=9B=D0=A06(MVC)=20=D0=BF=D0=BE=D1=85=D0=BE?= =?UTF-8?q?=D0=B6=D0=B5=20=D0=B3=D0=BE=D1=82=D0=BE=D0=B2=D0=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 4 + data.mv.db | Bin 102400 -> 86016 bytes .../DataBase/Repository/IUserRepository.java | 8 ++ .../is/lab1/DataBase/controller/UserDTO.java | 24 +++++ .../controller/UserMvcController.java | 39 ++++++++ .../DataBase/controller/UserSignupDTO.java | 34 +++++++ .../controller/UserSignupMvcController.java | 46 ++++++++++ .../ru/ulstu/is/lab1/DataBase/model/User.java | 83 ++++++++++++++++++ .../is/lab1/DataBase/model/UserRole.java | 17 ++++ .../is/lab1/DataBase/service/UserService.java | 61 +++++++++++++ .../is/lab1/PasswordEncoderConfiguration.java | 14 +++ .../ulstu/is/lab1/SecurityConfiguration.java | 68 ++++++++++++++ .../ru/ulstu/is/lab1/WebConfiguration.java | 2 +- .../util/validation/ValidationException.java | 2 + src/main/resources/templates/default.html | 4 +- src/main/resources/templates/login.html | 33 +++++++ src/main/resources/templates/signup.html | 31 +++++++ src/main/resources/templates/users.html | 40 +++++++++ 18 files changed, 508 insertions(+), 2 deletions(-) create mode 100644 src/main/java/ru/ulstu/is/lab1/DataBase/Repository/IUserRepository.java create mode 100644 src/main/java/ru/ulstu/is/lab1/DataBase/controller/UserDTO.java create mode 100644 src/main/java/ru/ulstu/is/lab1/DataBase/controller/UserMvcController.java create mode 100644 src/main/java/ru/ulstu/is/lab1/DataBase/controller/UserSignupDTO.java create mode 100644 src/main/java/ru/ulstu/is/lab1/DataBase/controller/UserSignupMvcController.java create mode 100644 src/main/java/ru/ulstu/is/lab1/DataBase/model/User.java create mode 100644 src/main/java/ru/ulstu/is/lab1/DataBase/model/UserRole.java create mode 100644 src/main/java/ru/ulstu/is/lab1/DataBase/service/UserService.java create mode 100644 src/main/java/ru/ulstu/is/lab1/PasswordEncoderConfiguration.java create mode 100644 src/main/java/ru/ulstu/is/lab1/SecurityConfiguration.java create mode 100644 src/main/resources/templates/login.html create mode 100644 src/main/resources/templates/signup.html create mode 100644 src/main/resources/templates/users.html diff --git a/build.gradle b/build.gradle index fe4e924..a721612 100644 --- a/build.gradle +++ b/build.gradle @@ -24,6 +24,10 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'com.h2database:h2:2.1.210' + + implementation 'org.springframework.boot:spring-boot-starter-security' + implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity5' + implementation 'org.hibernate.validator:hibernate-validator' implementation group: 'org.springdoc', name: 'springdoc-openapi-ui', version: '1.6.5' diff --git a/data.mv.db b/data.mv.db index 9b852fc3cd13d7253a64443d731eb422fb101c6f..52eb6864101e71c697ed1ab1f4f0e612f8622bba 100644 GIT binary patch literal 86016 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 Ni1!bd-}Q>){~xYed~E;# literal 102400 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 diff --git a/src/main/java/ru/ulstu/is/lab1/DataBase/Repository/IUserRepository.java b/src/main/java/ru/ulstu/is/lab1/DataBase/Repository/IUserRepository.java new file mode 100644 index 0000000..d9c9503 --- /dev/null +++ b/src/main/java/ru/ulstu/is/lab1/DataBase/Repository/IUserRepository.java @@ -0,0 +1,8 @@ +package ru.ulstu.is.lab1.DataBase.Repository; + +import ru.ulstu.is.lab1.DataBase.model.User; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface IUserRepository extends JpaRepository { + User findOneByLoginIgnoreCase(String login); +} diff --git a/src/main/java/ru/ulstu/is/lab1/DataBase/controller/UserDTO.java b/src/main/java/ru/ulstu/is/lab1/DataBase/controller/UserDTO.java new file mode 100644 index 0000000..f380f52 --- /dev/null +++ b/src/main/java/ru/ulstu/is/lab1/DataBase/controller/UserDTO.java @@ -0,0 +1,24 @@ +package ru.ulstu.is.lab1.DataBase.controller; + +import ru.ulstu.is.lab1.DataBase.model.User; +import ru.ulstu.is.lab1.DataBase.model.UserRole; + +public class UserDTO { + private final long id; + private final String login; + private final UserRole role; + public UserDTO(User user) { + this.id = user.getId(); + this.login = user.getLogin(); + this.role = user.getRole(); + } + public long getId() { + return id; + } + public String getLogin() { + return login; + } + public UserRole getRole() { + return role; + } +} diff --git a/src/main/java/ru/ulstu/is/lab1/DataBase/controller/UserMvcController.java b/src/main/java/ru/ulstu/is/lab1/DataBase/controller/UserMvcController.java new file mode 100644 index 0000000..12418a4 --- /dev/null +++ b/src/main/java/ru/ulstu/is/lab1/DataBase/controller/UserMvcController.java @@ -0,0 +1,39 @@ +package ru.ulstu.is.lab1.DataBase.controller; + +import ru.ulstu.is.lab1.DataBase.model.UserRole; +import ru.ulstu.is.lab1.DataBase.service.UserService; +import org.springframework.data.domain.Page; +import org.springframework.security.access.annotation.Secured; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; + +import java.util.List; +import java.util.stream.IntStream; + +@Controller +@RequestMapping("/users") +public class UserMvcController { + private final UserService userService; + public UserMvcController(UserService userService) { + this.userService = userService; + } + @GetMapping + @Secured({UserRole.AsString.ADMIN}) + public String getUsers(@RequestParam(defaultValue = "1") int page, + @RequestParam(defaultValue = "5") int size, + Model model) { + final Page users = userService.findAllPages(page, size) + .map(UserDTO::new); + model.addAttribute("users", users); + final int totalPages = users.getTotalPages(); + final List pageNumbers = IntStream.rangeClosed(1, totalPages) + .boxed() + .toList(); + model.addAttribute("pages", pageNumbers); + model.addAttribute("totalPages", totalPages); + return "users"; + } +} diff --git a/src/main/java/ru/ulstu/is/lab1/DataBase/controller/UserSignupDTO.java b/src/main/java/ru/ulstu/is/lab1/DataBase/controller/UserSignupDTO.java new file mode 100644 index 0000000..0c449fc --- /dev/null +++ b/src/main/java/ru/ulstu/is/lab1/DataBase/controller/UserSignupDTO.java @@ -0,0 +1,34 @@ +package ru.ulstu.is.lab1.DataBase.controller; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.Size; + +public class UserSignupDTO { + @NotBlank + @Size(min = 3, max = 64) + private String login; + @NotBlank + @Size(min = 6, max = 64) + private String password; + @NotBlank + @Size(min = 6, max = 64) + private String passwordConfirm; + public String getLogin() { + return login; + } + public void setLogin(String login) { + this.login = login; + } + public String getPassword() { + return password; + } + public void setPassword(String password) { + this.password = password; + } + public String getPasswordConfirm() { + return passwordConfirm; + } + public void setPasswordConfirm(String passwordConfirm) { + this.passwordConfirm = passwordConfirm; + } +} diff --git a/src/main/java/ru/ulstu/is/lab1/DataBase/controller/UserSignupMvcController.java b/src/main/java/ru/ulstu/is/lab1/DataBase/controller/UserSignupMvcController.java new file mode 100644 index 0000000..16d30e8 --- /dev/null +++ b/src/main/java/ru/ulstu/is/lab1/DataBase/controller/UserSignupMvcController.java @@ -0,0 +1,46 @@ +package ru.ulstu.is.lab1.DataBase.controller; + +import ru.ulstu.is.lab1.DataBase.model.User; +import ru.ulstu.is.lab1.DataBase.service.UserService; +import ru.ulstu.is.lab1.util.validation.ValidationException; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.validation.BindingResult; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; + +import javax.validation.Valid; + +@Controller +@RequestMapping(UserSignupMvcController.SIGNUP_URL) +public class UserSignupMvcController { + public static final String SIGNUP_URL = "/signup"; + private final UserService userService; + public UserSignupMvcController(UserService userService) { + this.userService = userService; + } + @GetMapping + public String showSignupForm(Model model) { + model.addAttribute("UserDTO", new UserSignupDTO()); + return "signup"; + } + @PostMapping + public String signup(@ModelAttribute("UserDTO") @Valid UserSignupDTO userSignupDTO, + BindingResult bindingResult, + Model model) { + if (bindingResult.hasErrors()) { + model.addAttribute("errors", bindingResult.getAllErrors()); + return "signup"; + } + try { + final User user = userService.createUser( + userSignupDTO.getLogin(), userSignupDTO.getPassword(), userSignupDTO.getPasswordConfirm()); + return "redirect:/login?created=" + user.getLogin(); + } catch (ValidationException e) { + model.addAttribute("errors", e.getMessage()); + return "signup"; + } + } +} diff --git a/src/main/java/ru/ulstu/is/lab1/DataBase/model/User.java b/src/main/java/ru/ulstu/is/lab1/DataBase/model/User.java new file mode 100644 index 0000000..5408a8c --- /dev/null +++ b/src/main/java/ru/ulstu/is/lab1/DataBase/model/User.java @@ -0,0 +1,83 @@ +package ru.ulstu.is.lab1.DataBase.model; + +import javax.persistence.*; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.Size; +import java.util.Objects; + +@Entity +@Table(name = "users") +public class User +{ + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + private Long id; + @Column(nullable = false, unique = true, length = 64) + @NotBlank + @Size(min = 3, max = 64) + private String login; + @Column(nullable = false, length = 64) + @NotBlank + @Size(min = 6, max = 64) + private String password; + private UserRole role; + + public User() { + } + + public User(String login, String password) { + this(login, password, UserRole.USER); + } + + public User(String login, String password, UserRole role) { + this.login = login; + this.password = password; + this.role = role; + } + + public Long getId() { + return id; + } + + public String getLogin() { + return login; + } + + public void setLogin(String login) { + this.login = login; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public UserRole getRole() { + return role; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + User user = (User) o; + return Objects.equals(id, user.id) && Objects.equals(login, user.login); + } + + @Override + public int hashCode() { + return Objects.hash(id, login); + } + @Override + public String toString() { + return "User{" + + "id=" + id + + ", login='" + login + '\'' + + ", password='" + password + '\'' + + ", role='" + role + '\'' + + '}'; + } +} diff --git a/src/main/java/ru/ulstu/is/lab1/DataBase/model/UserRole.java b/src/main/java/ru/ulstu/is/lab1/DataBase/model/UserRole.java new file mode 100644 index 0000000..8788472 --- /dev/null +++ b/src/main/java/ru/ulstu/is/lab1/DataBase/model/UserRole.java @@ -0,0 +1,17 @@ +package ru.ulstu.is.lab1.DataBase.model; + +import org.springframework.security.core.GrantedAuthority; + +public enum UserRole implements GrantedAuthority { + ADMIN, + USER; + private static final String PREFIX = "ROLE_"; + @Override + public String getAuthority() { + return PREFIX + this.name(); + } + public static final class AsString { + public static final String ADMIN = PREFIX + "ADMIN"; + public static final String USER = PREFIX + "USER"; + } +} diff --git a/src/main/java/ru/ulstu/is/lab1/DataBase/service/UserService.java b/src/main/java/ru/ulstu/is/lab1/DataBase/service/UserService.java new file mode 100644 index 0000000..f445643 --- /dev/null +++ b/src/main/java/ru/ulstu/is/lab1/DataBase/service/UserService.java @@ -0,0 +1,61 @@ +package ru.ulstu.is.lab1.DataBase.service; + +import ru.ulstu.is.lab1.DataBase.model.User; +import ru.ulstu.is.lab1.DataBase.model.UserRole; +import ru.ulstu.is.lab1.DataBase.Repository.IUserRepository; +import ru.ulstu.is.lab1.util.validation.ValidationException; +import ru.ulstu.is.lab1.util.validation.ValidatorUtil; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Sort; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.stereotype.Service; + +import java.util.Collections; +import java.util.Objects; + +@Service +public class UserService implements UserDetailsService { + private final IUserRepository userRepository; + private final PasswordEncoder passwordEncoder; + private final ValidatorUtil validatorUtil; + public UserService(IUserRepository userRepository, + PasswordEncoder passwordEncoder, + ValidatorUtil validatorUtil) { + this.userRepository = userRepository; + this.passwordEncoder = passwordEncoder; + this.validatorUtil = validatorUtil; + } + public Page findAllPages(int page, int size) { + return userRepository.findAll(PageRequest.of(page - 1, size, Sort.by("id").ascending())); + } + public User findByLogin(String login) { + return userRepository.findOneByLoginIgnoreCase(login); + } + public User createUser(String login, String password, String passwordConfirm) { + return createUser(login, password, passwordConfirm, UserRole.USER); + } + public User createUser(String login, String password, String passwordConfirm, UserRole role) { + if (findByLogin(login) != null) { + throw new ValidationException(String.format("User '%s' already exists", login)); + } + final User user = new User(login, passwordEncoder.encode(password), role); + validatorUtil.validate(user); + if (!Objects.equals(password, passwordConfirm)) { + throw new ValidationException("Passwords not equals"); + } + return userRepository.save(user); + } + @Override + public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { + final User userEntity = findByLogin(username); + if (userEntity == null) { + throw new UsernameNotFoundException(username); + } + return new org.springframework.security.core.userdetails.User( + userEntity.getLogin(), userEntity.getPassword(), Collections.singleton(userEntity.getRole())); + } +} diff --git a/src/main/java/ru/ulstu/is/lab1/PasswordEncoderConfiguration.java b/src/main/java/ru/ulstu/is/lab1/PasswordEncoderConfiguration.java new file mode 100644 index 0000000..3e62ac6 --- /dev/null +++ b/src/main/java/ru/ulstu/is/lab1/PasswordEncoderConfiguration.java @@ -0,0 +1,14 @@ +package ru.ulstu.is.lab1; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; + +@Configuration +public class PasswordEncoderConfiguration { + @Bean + public PasswordEncoder createPasswordEncoder() { + return new BCryptPasswordEncoder(); + } +} \ No newline at end of file diff --git a/src/main/java/ru/ulstu/is/lab1/SecurityConfiguration.java b/src/main/java/ru/ulstu/is/lab1/SecurityConfiguration.java new file mode 100644 index 0000000..59137bc --- /dev/null +++ b/src/main/java/ru/ulstu/is/lab1/SecurityConfiguration.java @@ -0,0 +1,68 @@ +package ru.ulstu.is.lab1; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpMethod; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.builders.WebSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import ru.ulstu.is.lab1.DataBase.controller.UserSignupMvcController; +import ru.ulstu.is.lab1.DataBase.model.UserRole; +import ru.ulstu.is.lab1.DataBase.service.UserService; + +@Configuration +@EnableWebSecurity +@EnableGlobalMethodSecurity(securedEnabled = true) +public class SecurityConfiguration extends WebSecurityConfigurerAdapter { + private final Logger log = LoggerFactory.getLogger(SecurityConfiguration.class); + private static final String LOGIN_URL = "/login"; + private final UserService userService; + + public SecurityConfiguration(UserService userService) { + this.userService = userService; + createAdminOnStartup(); + } + + private void createAdminOnStartup() { + final String admin = "admin"; + if (userService.findByLogin(admin) == null) { + log.info("Admin user successfully created"); + userService.createUser(admin, admin, admin, UserRole.ADMIN); + } + } + + @Override + protected void configure(HttpSecurity http) throws Exception { + http.headers().frameOptions().sameOrigin().and() + .cors().and() + .csrf().disable() + .authorizeRequests() + .antMatchers(UserSignupMvcController.SIGNUP_URL).permitAll() + .antMatchers(HttpMethod.GET, LOGIN_URL).permitAll() + .anyRequest().authenticated() + .and() + .formLogin() + .loginPage(LOGIN_URL).permitAll() + .and() + .logout().permitAll(); + } + + @Override + protected void configure(AuthenticationManagerBuilder auth) throws Exception { + auth.userDetailsService(userService); + } + + @Override + public void configure(WebSecurity web) { + web.ignoring() + .antMatchers("/css/**") + .antMatchers("/images/**") + .antMatchers("/js/**") + .antMatchers("/templates/**") + .antMatchers("/webjars/**"); + } +} diff --git a/src/main/java/ru/ulstu/is/lab1/WebConfiguration.java b/src/main/java/ru/ulstu/is/lab1/WebConfiguration.java index 4f079e4..29f56e7 100644 --- a/src/main/java/ru/ulstu/is/lab1/WebConfiguration.java +++ b/src/main/java/ru/ulstu/is/lab1/WebConfiguration.java @@ -11,7 +11,7 @@ public class WebConfiguration implements WebMvcConfigurer { @Override public void addViewControllers(ViewControllerRegistry registry) { WebMvcConfigurer.super.addViewControllers(registry); - registry.addViewController("rest-test"); + registry.addViewController("login"); } @Override public void addCorsMappings(CorsRegistry registry){ diff --git a/src/main/java/ru/ulstu/is/lab1/util/validation/ValidationException.java b/src/main/java/ru/ulstu/is/lab1/util/validation/ValidationException.java index fe4527b..34b4f74 100644 --- a/src/main/java/ru/ulstu/is/lab1/util/validation/ValidationException.java +++ b/src/main/java/ru/ulstu/is/lab1/util/validation/ValidationException.java @@ -6,4 +6,6 @@ public class ValidationException extends RuntimeException{ public ValidationException(Set errors) { super(String.join("\n", errors)); } + + public ValidationException(String error) { super(error); } } diff --git a/src/main/resources/templates/default.html b/src/main/resources/templates/default.html index 29bdbb5..05f268e 100644 --- a/src/main/resources/templates/default.html +++ b/src/main/resources/templates/default.html @@ -13,7 +13,7 @@
-