From 4a6f146039d039111d1548c3c123bc34294437a2 Mon Sep 17 00:00:00 2001 From: abazov73 <92822431+abazov73@users.noreply.github.com> Date: Mon, 15 May 2023 22:32:53 +0400 Subject: [PATCH] =?UTF-8?q?=D0=A8=D0=B5=D1=81=D1=82=D0=B0=D1=8F=20=D0=BB?= =?UTF-8?q?=D0=B0=D0=B1=D0=BE=D1=80=D0=B0=D1=82=D0=BE=D1=80=D0=BD=D0=B0?= =?UTF-8?q?=D1=8F=20=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D0=B0.=20=D0=90=D1=83?= =?UTF-8?q?=D0=BD=D1=82=D0=B5=D1=84=D0=B8=D0=BA=D0=B0=D1=86=D0=B8=D1=8F=20?= =?UTF-8?q?=D0=B2=20MVC=20+=20=D0=BE=D0=B1=D1=80=D0=B0=D0=B1=D0=BE=D1=82?= =?UTF-8?q?=D0=BA=D0=B0=20=D1=82=D0=BE=D0=BA=D0=B5=D0=BD=D0=BE=D0=B2=20?= =?UTF-8?q?=D1=87=D0=B5=D1=80=D0=B5=D0=B7=20JWT.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/ipLab/build.gradle | 6 ++ backend/ipLab/data.mv.db | Bin 94208 -> 106496 bytes .../PasswordEncoderConfiguration.java | 14 +++ .../Configurations/SecurityConfiguration.java | 87 ++++++++++++++++ .../Configurations/jwt/JwtException.java | 11 ++ .../Configurations/jwt/JwtFilter.java | 92 +++++++++++++++++ .../Configurations/jwt/JwtProperties.java | 27 +++++ .../Configurations/jwt/JwtsProvider.java | 47 +++++++++ .../Controllers/UserController.java | 24 +++++ .../ipLab/StoreDataBase/DTO/LoginDTO.java | 36 +++++++ .../ipLab/StoreDataBase/DTO/UserDTO.java | 49 +++++++++ .../Exceptions/UserNotFoundException.java | 7 ++ .../MVC/OrderedMVCController.java | 21 +++- .../MVC/ProductMVCController.java | 31 +++++- .../MVC/UserLoginMVCController.java | 51 +++++++++ .../StoreDataBase/MVC/UserMVCController.java | 33 ++++++ .../ipLab/StoreDataBase/Model/CustomUser.java | 26 +++++ .../ipLab/StoreDataBase/Model/User.java | 76 ++++++++++++++ .../ipLab/StoreDataBase/Model/UserRole.java | 20 ++++ .../Repositories/OrderedRepository.java | 6 ++ .../Repositories/UserRepository.java | 8 ++ .../StoreDataBase/Service/OrderService.java | 5 + .../StoreDataBase/Service/ProductService.java | 1 - .../StoreDataBase/Service/UserService.java | 97 ++++++++++++++++++ .../util/error/AdviceController.java | 9 ++ .../util/validation/ValidationException.java | 4 + .../com/example/ipLab/WebConfiguration.java | 7 ++ .../src/main/resources/application.properties | 3 + .../src/main/resources/static/img/logo.png | Bin 0 -> 9949 bytes .../main/resources/templates/addToStore.html | 2 +- .../main/resources/templates/customer.html | 4 +- .../src/main/resources/templates/default.html | 8 +- .../src/main/resources/templates/index.html | 2 +- .../src/main/resources/templates/login.html | 43 ++++++++ .../src/main/resources/templates/order.html | 2 +- .../src/main/resources/templates/product.html | 6 +- .../src/main/resources/templates/signup.html | 28 +++++ .../src/main/resources/templates/store.html | 6 +- .../src/main/resources/templates/users.html | 27 +++++ 39 files changed, 902 insertions(+), 24 deletions(-) create mode 100644 backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/Configurations/PasswordEncoderConfiguration.java create mode 100644 backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/Configurations/SecurityConfiguration.java create mode 100644 backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/Configurations/jwt/JwtException.java create mode 100644 backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/Configurations/jwt/JwtFilter.java create mode 100644 backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/Configurations/jwt/JwtProperties.java create mode 100644 backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/Configurations/jwt/JwtsProvider.java create mode 100644 backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/Controllers/UserController.java create mode 100644 backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/DTO/LoginDTO.java create mode 100644 backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/DTO/UserDTO.java create mode 100644 backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/Exceptions/UserNotFoundException.java create mode 100644 backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/MVC/UserLoginMVCController.java create mode 100644 backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/MVC/UserMVCController.java create mode 100644 backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/Model/CustomUser.java create mode 100644 backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/Model/User.java create mode 100644 backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/Model/UserRole.java create mode 100644 backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/Repositories/UserRepository.java create mode 100644 backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/Service/UserService.java create mode 100644 backend/ipLab/src/main/resources/static/img/logo.png create mode 100644 backend/ipLab/src/main/resources/templates/login.html create mode 100644 backend/ipLab/src/main/resources/templates/signup.html create mode 100644 backend/ipLab/src/main/resources/templates/users.html diff --git a/backend/ipLab/build.gradle b/backend/ipLab/build.gradle index 8e65326..7cea6c2 100644 --- a/backend/ipLab/build.gradle +++ b/backend/ipLab/build.gradle @@ -30,6 +30,12 @@ dependencies { implementation 'org.webjars:bootstrap:5.1.3' implementation 'org.webjars:jquery:3.6.0' implementation 'org.webjars:font-awesome:6.1.0' + + implementation 'org.springframework.boot:spring-boot-starter-security' + implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity6' + implementation 'com.auth0:java-jwt:4.4.0' + implementation group: 'io.jsonwebtoken', name: 'jjwt', version: '0.9.1' + implementation 'javax.xml.bind:jaxb-api:2.3.1' } tasks.named('test') { diff --git a/backend/ipLab/data.mv.db b/backend/ipLab/data.mv.db index fcff4ed4c8b4fb24dcd34e5c5e41f1106c932e8d..cd412bd32bebea4c3e9a1cd17d35548755975f2c 100644 GIT binary patch delta 12157 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 a + .requestMatchers(HttpMethod.DELETE, "/api/**").hasRole("ADMIN") + .requestMatchers(HttpMethod.PUT, "/api/**").hasRole("ADMIN") + .requestMatchers(HttpMethod.POST, "/api/**").hasRole("ADMIN") + .requestMatchers("/api/**").authenticated() + .requestMatchers(HttpMethod.POST, UserController.URL_LOGIN).permitAll() + .requestMatchers(HttpMethod.GET, "/img/**").permitAll()) + .addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class) + .anonymous().and().authorizeHttpRequests((a) -> + a.requestMatchers(LOGIN_URL, UserLoginMVCController.SIGNUP_URL, "/h2-console/**") + .permitAll().requestMatchers("/users").hasRole("ADMIN").anyRequest().authenticated()) + .formLogin() + .loginPage(LOGIN_URL).permitAll() + .defaultSuccessUrl("/", true) + .and() + .logout().permitAll() + .logoutSuccessUrl("/login") + .and() + .userDetailsService(userService); + return http.build(); + } + @Bean + public WebSecurityCustomizer webSecurityCustomizer() { + return (web) -> web.ignoring().requestMatchers("/css/**", "/js/**", "/templates/**", "/webjars/**", "/styles/**"); + } +} diff --git a/backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/Configurations/jwt/JwtException.java b/backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/Configurations/jwt/JwtException.java new file mode 100644 index 0000000..14261ef --- /dev/null +++ b/backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/Configurations/jwt/JwtException.java @@ -0,0 +1,11 @@ +package com.example.ipLab.StoreDataBase.Configurations.jwt; + +public class JwtException extends RuntimeException{ + public JwtException(Throwable throwable) { + super(throwable); + } + + public JwtException(String message) { + super(message); + } +} diff --git a/backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/Configurations/jwt/JwtFilter.java b/backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/Configurations/jwt/JwtFilter.java new file mode 100644 index 0000000..2dc19d8 --- /dev/null +++ b/backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/Configurations/jwt/JwtFilter.java @@ -0,0 +1,92 @@ +package com.example.ipLab.StoreDataBase.Configurations.jwt; + +import com.example.ipLab.StoreDataBase.Service.UserService; +import com.fasterxml.jackson.databind.ObjectMapper; +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.ServletRequest; +import jakarta.servlet.ServletResponse; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.http.MediaType; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; +import org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter; +import org.springframework.util.StringUtils; + +import java.io.IOException; + +public class JwtFilter extends AbstractPreAuthenticatedProcessingFilter { + private static final String AUTHORIZATION = "Authorization"; + public static final String TOKEN_BEGIN_STR = "Bearer "; + + private final UserService userService; + + public JwtFilter(UserService userService) { + this.userService = userService; + } + + private String getTokenFromRequest(HttpServletRequest request) { + String bearer = request.getHeader(AUTHORIZATION); + if (StringUtils.hasText(bearer) && bearer.startsWith(TOKEN_BEGIN_STR)) { + return bearer.substring(TOKEN_BEGIN_STR.length()); + } + return null; + } + + private void raiseException(ServletResponse response, int status, String message) throws IOException { + if (response instanceof final HttpServletResponse httpResponse) { + httpResponse.setContentType(MediaType.APPLICATION_JSON_VALUE); + httpResponse.setStatus(status); + final byte[] body = new ObjectMapper().writeValueAsBytes(message); + response.getOutputStream().write(body); + } + } + + @Override + public void doFilter(ServletRequest request, + ServletResponse response, + FilterChain chain) throws IOException, ServletException { + if (request instanceof final HttpServletRequest httpRequest) { + final String token = getTokenFromRequest(httpRequest); + if (StringUtils.hasText(token)) { + try { + final UserDetails user = userService.loadUserByToken(token); + final UsernamePasswordAuthenticationToken auth = + new UsernamePasswordAuthenticationToken(user, null, user.getAuthorities()); + SecurityContextHolder.getContext().setAuthentication(auth); + } catch (JwtException e) { + raiseException(response, HttpServletResponse.SC_UNAUTHORIZED, e.getMessage()); + return; + } catch (Exception e) { + e.printStackTrace(); + raiseException(response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, + String.format("Internal error: %s", e.getMessage())); + return; + } + } + } + HttpServletRequest httpRequest = (HttpServletRequest) request; + if (httpRequest.getRequestURI().startsWith("/api/")) { + // Для URL, начинающихся с /api/, выполняем проверку наличия токена + super.doFilter(request, response, chain); + } else { + // Для остальных URL выполняем авторизацию + chain.doFilter(request, response); + } + } + + @Override + protected Object getPreAuthenticatedPrincipal(HttpServletRequest request) { + String token = getTokenFromRequest(request); + // Возвращаем токен как принципала + return token; + } + + @Override + protected Object getPreAuthenticatedCredentials(HttpServletRequest request) { + return new WebAuthenticationDetailsSource().buildDetails(request); + } +} diff --git a/backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/Configurations/jwt/JwtProperties.java b/backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/Configurations/jwt/JwtProperties.java new file mode 100644 index 0000000..8553d2e --- /dev/null +++ b/backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/Configurations/jwt/JwtProperties.java @@ -0,0 +1,27 @@ +package com.example.ipLab.StoreDataBase.Configurations.jwt; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +@Configuration +@ConfigurationProperties(prefix = "jwt", ignoreInvalidFields = true) +public class JwtProperties { + private String devToken = ""; + private Boolean isDev = true; + + public String getDevToken() { + return devToken; + } + + public void setDevToken(String devToken) { + this.devToken = devToken; + } + + public Boolean isDev() { + return isDev; + } + + public void setDev(Boolean dev) { + isDev = dev; + } +} diff --git a/backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/Configurations/jwt/JwtsProvider.java b/backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/Configurations/jwt/JwtsProvider.java new file mode 100644 index 0000000..f6d76f9 --- /dev/null +++ b/backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/Configurations/jwt/JwtsProvider.java @@ -0,0 +1,47 @@ +package com.example.ipLab.StoreDataBase.Configurations.jwt; + +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.JwtBuilder; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.SignatureAlgorithm; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import java.time.LocalDate; +import java.time.ZoneId; +import java.util.Date; +@Component +public class JwtsProvider { + @Value("jwt.secret") + private String secret; + + public String generateToken(String login, String role) { + Date date = Date.from(LocalDate.now().plusDays(15).atStartOfDay(ZoneId.systemDefault()).toInstant()); + + JwtBuilder builder = Jwts.builder() + .setSubject(login) + .setExpiration(date) + .signWith(SignatureAlgorithm.HS512, secret); + Claims claims = Jwts.claims(); + claims.put("role", role); + builder.addClaims(claims); + return builder.compact(); + } + + public boolean validateToken(String token) { + try { + Jwts.parser().setSigningKey(secret).parseClaimsJws(token); + return true; + } catch (Exception e) { + return false; + } + } + + public String getLogin(String token) { + return Jwts.parser() + .setSigningKey(secret) + .parseClaimsJws(token) + .getBody() + .getSubject(); + } +} diff --git a/backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/Controllers/UserController.java b/backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/Controllers/UserController.java new file mode 100644 index 0000000..52e977a --- /dev/null +++ b/backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/Controllers/UserController.java @@ -0,0 +1,24 @@ +package com.example.ipLab.StoreDataBase.Controllers; + +import com.example.ipLab.StoreDataBase.DTO.UserDTO; +import com.example.ipLab.StoreDataBase.Service.UserService; +import jakarta.validation.Valid; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class UserController { + public static final String URL_LOGIN = "/jwt/login"; + + private final UserService userService; + + public UserController(UserService userService) { + this.userService = userService; + } + + @PostMapping(URL_LOGIN) + public String login(@RequestBody @Valid UserDTO userDto) { + return userService.loginAndGetToken(userDto); + } +} diff --git a/backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/DTO/LoginDTO.java b/backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/DTO/LoginDTO.java new file mode 100644 index 0000000..4975dd6 --- /dev/null +++ b/backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/DTO/LoginDTO.java @@ -0,0 +1,36 @@ +package com.example.ipLab.StoreDataBase.DTO; + +import jakarta.validation.constraints.NotBlank; + +public class LoginDTO { + @NotBlank + private String login; + @NotBlank + private String password; + @NotBlank + 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/backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/DTO/UserDTO.java b/backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/DTO/UserDTO.java new file mode 100644 index 0000000..fa471e7 --- /dev/null +++ b/backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/DTO/UserDTO.java @@ -0,0 +1,49 @@ +package com.example.ipLab.StoreDataBase.DTO; + +import com.example.ipLab.StoreDataBase.Model.User; +import com.example.ipLab.StoreDataBase.Model.UserRole; + +public class UserDTO { + private long id; + private String login; + private UserRole role; + private String password; + + public UserDTO() { + } + + public UserDTO(User user) { + this.id = user.getId(); + this.login = user.getLogin(); + this.role = user.getRole(); + this.password = user.getPassword(); + } + + public long getId() { + return id; + } + + public String getLogin() { + return login; + } + + public UserRole getRole() { + return role; + } + + public String getPassword() { + return password; + } + + public void setLogin(String login) { + this.login = login; + } + + public void setRole(UserRole role) { + this.role = role; + } + + public void setPassword(String password) { + this.password = password; + } +} diff --git a/backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/Exceptions/UserNotFoundException.java b/backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/Exceptions/UserNotFoundException.java new file mode 100644 index 0000000..ede9957 --- /dev/null +++ b/backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/Exceptions/UserNotFoundException.java @@ -0,0 +1,7 @@ +package com.example.ipLab.StoreDataBase.Exceptions; + +public class UserNotFoundException extends RuntimeException{ + public UserNotFoundException(String login){ + super(String.format("User with login: %s hasn't been found", login)); + } +} diff --git a/backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/MVC/OrderedMVCController.java b/backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/MVC/OrderedMVCController.java index 10018f9..02d498e 100644 --- a/backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/MVC/OrderedMVCController.java +++ b/backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/MVC/OrderedMVCController.java @@ -3,10 +3,13 @@ package com.example.ipLab.StoreDataBase.MVC; import com.example.ipLab.StoreDataBase.DTO.CustomerDTO; import com.example.ipLab.StoreDataBase.DTO.OrderedDTO; import com.example.ipLab.StoreDataBase.DTO.ProductDTO; +import com.example.ipLab.StoreDataBase.Model.CustomUser; +import com.example.ipLab.StoreDataBase.Model.UserRole; import com.example.ipLab.StoreDataBase.Service.CustomerService; import com.example.ipLab.StoreDataBase.Service.OrderService; import com.example.ipLab.StoreDataBase.Service.ProductService; import jakarta.validation.Valid; +import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.validation.BindingResult; @@ -26,11 +29,19 @@ public class OrderedMVCController { } @GetMapping - public String getOrdereds(Model model) { - model.addAttribute("orders", - orderedService.getAllOrders().stream() - .map(OrderedDTO::new) - .toList()); + public String getOrdereds(Model model, @AuthenticationPrincipal CustomUser user) { + if (user.getRole() == UserRole.USER){ + model.addAttribute("orders", + orderedService.getOrdersByCustomerId(user.getUserID()).stream() + .map(OrderedDTO::new) + .toList()); + } + else { + model.addAttribute("orders", + orderedService.getAllOrders().stream() + .map(OrderedDTO::new) + .toList()); + } return "order"; } diff --git a/backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/MVC/ProductMVCController.java b/backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/MVC/ProductMVCController.java index 305ff2f..880cd25 100644 --- a/backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/MVC/ProductMVCController.java +++ b/backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/MVC/ProductMVCController.java @@ -1,13 +1,24 @@ package com.example.ipLab.StoreDataBase.MVC; +import com.example.ipLab.StoreDataBase.Configurations.SecurityConfiguration; import com.example.ipLab.StoreDataBase.DTO.ProductDTO; +import com.example.ipLab.StoreDataBase.Model.CustomUser; +import com.example.ipLab.StoreDataBase.Model.User; +import com.example.ipLab.StoreDataBase.Model.UserRole; import com.example.ipLab.StoreDataBase.Service.ProductService; +import com.example.ipLab.StoreDataBase.Service.UserService; import jakarta.validation.Valid; +import org.springframework.security.authentication.AnonymousAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.validation.BindingResult; import org.springframework.web.bind.annotation.*; +import java.security.Principal; + @Controller @RequestMapping("/product") public class ProductMVCController { @@ -18,11 +29,21 @@ public class ProductMVCController { } @GetMapping - public String getProducts(Model model) { - model.addAttribute("products", - productService.getAllProducts().stream() - .map(ProductDTO::new) - .toList()); + + public String getProducts(Model model, @AuthenticationPrincipal CustomUser user) { + if (user.getRole() == UserRole.USER){ + model.addAttribute("products", + productService.getAllProductsWithStores().stream() + .map(ProductDTO::new) + .toList()); + } + else{ + model.addAttribute("products", + productService.getAllProducts().stream() + .map(ProductDTO::new) + .toList()); + } + return "product"; } diff --git a/backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/MVC/UserLoginMVCController.java b/backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/MVC/UserLoginMVCController.java new file mode 100644 index 0000000..2a5d192 --- /dev/null +++ b/backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/MVC/UserLoginMVCController.java @@ -0,0 +1,51 @@ +package com.example.ipLab.StoreDataBase.MVC; + +import com.example.ipLab.StoreDataBase.DTO.LoginDTO; +import com.example.ipLab.StoreDataBase.Model.User; +import com.example.ipLab.StoreDataBase.Model.UserRole; +import com.example.ipLab.StoreDataBase.Service.UserService; +import com.example.ipLab.StoreDataBase.util.validation.ValidationException; +import jakarta.validation.Valid; +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; + +@Controller +@RequestMapping(UserLoginMVCController.SIGNUP_URL) +public class UserLoginMVCController { + public static final String SIGNUP_URL = "/signup"; + + private final UserService userService; + + public UserLoginMVCController(UserService userService) { + this.userService = userService; + } + + @GetMapping + public String showSignupForm(Model model) { + model.addAttribute("userDto", new LoginDTO()); + return "signup"; + } + + @PostMapping + public String signup(@ModelAttribute("userDto") @Valid LoginDTO userSignupDto, + BindingResult bindingResult, + Model model) { + if (bindingResult.hasErrors()) { + model.addAttribute("errors", bindingResult.getAllErrors()); + return "signup"; + } + try { + final User user = userService.addUser( + userSignupDto.getLogin(), userSignupDto.getPassword(), userSignupDto.getPasswordConfirm(), UserRole.USER, Long.parseLong("1")); + return "redirect:/login?created=" + user.getLogin(); + } catch (ValidationException e) { + model.addAttribute("errors", e.getMessage()); + return "signup"; + } + } +} diff --git a/backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/MVC/UserMVCController.java b/backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/MVC/UserMVCController.java new file mode 100644 index 0000000..3659995 --- /dev/null +++ b/backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/MVC/UserMVCController.java @@ -0,0 +1,33 @@ +package com.example.ipLab.StoreDataBase.MVC; + +import com.example.ipLab.StoreDataBase.DTO.ProductDTO; +import com.example.ipLab.StoreDataBase.DTO.UserDTO; +import com.example.ipLab.StoreDataBase.Model.UserRole; +import com.example.ipLab.StoreDataBase.Service.UserService; +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; + +@Controller +@RequestMapping("/user") +public class UserMVCController { + private final UserService userService; + + public UserMVCController(UserService userService) { + this.userService = userService; + } + + @GetMapping + @Secured({UserRole.AsString.ADMIN}) + public String getUsers(Model model){ + model.addAttribute("users", + userService.getAllUsers().stream() + .map(UserDTO::new) + .toList()); + return "users"; + } + + +} diff --git a/backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/Model/CustomUser.java b/backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/Model/CustomUser.java new file mode 100644 index 0000000..05ed8f0 --- /dev/null +++ b/backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/Model/CustomUser.java @@ -0,0 +1,26 @@ +package com.example.ipLab.StoreDataBase.Model; + +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.userdetails.User; + +import java.util.Collection; + +public class CustomUser extends User { + private final Long userID; + private final UserRole role; + + public CustomUser(String username, String password, + Collection authorities, Long userID, UserRole role) { + super(username, password, authorities); + this.userID = userID; + this.role = role; + } + + public Long getUserID() { + return userID; + } + + public UserRole getRole() { + return role; + } +} diff --git a/backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/Model/User.java b/backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/Model/User.java new file mode 100644 index 0000000..aeead35 --- /dev/null +++ b/backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/Model/User.java @@ -0,0 +1,76 @@ +package com.example.ipLab.StoreDataBase.Model; + +import jakarta.persistence.*; +import jakarta.validation.constraints.NotBlank; + +import java.util.Objects; + +@Entity +@Table(name = "users") +public class User { + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + private Long id; + @Column + @NotBlank + private String login; + @Column + @NotBlank + private String password; + @Column + @NotBlank + private Long userId; + + private UserRole role; + + public User() { + } + + public User(String login, String password, Long userId) { + this(login, password, UserRole.USER, userId); + } + + public User(String login, String password, UserRole role, Long userId) { + this.login = login; + this.password = password; + this.role = role; + this.userId = userId; + } + + 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); + } +} diff --git a/backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/Model/UserRole.java b/backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/Model/UserRole.java new file mode 100644 index 0000000..aa77b24 --- /dev/null +++ b/backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/Model/UserRole.java @@ -0,0 +1,20 @@ +package com.example.ipLab.StoreDataBase.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/backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/Repositories/OrderedRepository.java b/backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/Repositories/OrderedRepository.java index 45a6129..ce6489e 100644 --- a/backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/Repositories/OrderedRepository.java +++ b/backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/Repositories/OrderedRepository.java @@ -1,7 +1,13 @@ package com.example.ipLab.StoreDataBase.Repositories; import com.example.ipLab.StoreDataBase.Model.Ordered; +import com.example.ipLab.StoreDataBase.Model.Product; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; + +import java.util.Collection; public interface OrderedRepository extends JpaRepository { + @Query("SELECT o FROM Ordered o WHERE o.customer.id = ?1") + Collection findOrdersByCustomerId(Long clientId); } diff --git a/backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/Repositories/UserRepository.java b/backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/Repositories/UserRepository.java new file mode 100644 index 0000000..1f248f2 --- /dev/null +++ b/backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/Repositories/UserRepository.java @@ -0,0 +1,8 @@ +package com.example.ipLab.StoreDataBase.Repositories; + +import com.example.ipLab.StoreDataBase.Model.User; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface UserRepository extends JpaRepository { + User findOneByLogin(String login); +} diff --git a/backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/Service/OrderService.java b/backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/Service/OrderService.java index 2ce83e4..bc4cce0 100644 --- a/backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/Service/OrderService.java +++ b/backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/Service/OrderService.java @@ -52,6 +52,11 @@ public class OrderService { return orderedRepository.findAll(); } + @Transactional + public List getOrdersByCustomerId(Long customerId){ + return orderedRepository.findOrdersByCustomerId(customerId).stream().toList(); + } + @Transactional public Ordered updateOrder(Long id, int quantity){ final Ordered order = getOrder(id); diff --git a/backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/Service/ProductService.java b/backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/Service/ProductService.java index 6668ce1..83593bd 100644 --- a/backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/Service/ProductService.java +++ b/backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/Service/ProductService.java @@ -36,7 +36,6 @@ public class ProductService { public Product getProduct(Long id){ return productRepository.findById(id).orElseThrow(() -> new ProductNotFoundException(id)); } - @Transactional public List getAllProducts(){ return productRepository.findAll(); diff --git a/backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/Service/UserService.java b/backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/Service/UserService.java new file mode 100644 index 0000000..951735e --- /dev/null +++ b/backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/Service/UserService.java @@ -0,0 +1,97 @@ +package com.example.ipLab.StoreDataBase.Service; + +import com.example.ipLab.StoreDataBase.Configurations.jwt.JwtException; +import com.example.ipLab.StoreDataBase.Configurations.jwt.JwtsProvider; +import com.example.ipLab.StoreDataBase.DTO.UserDTO; +import com.example.ipLab.StoreDataBase.Exceptions.CustomerNotFoundException; +import com.example.ipLab.StoreDataBase.Exceptions.UserNotFoundException; +import com.example.ipLab.StoreDataBase.Model.CustomUser; +import com.example.ipLab.StoreDataBase.Model.Customer; +import com.example.ipLab.StoreDataBase.Model.User; +import com.example.ipLab.StoreDataBase.Model.UserRole; +import com.example.ipLab.StoreDataBase.Repositories.UserRepository; +import com.example.ipLab.StoreDataBase.util.validation.ValidationException; +import com.example.ipLab.StoreDataBase.util.validation.ValidatorUtil; +import jakarta.transaction.Transactional; +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.List; +import java.util.Objects; + +@Service +public class UserService implements UserDetailsService { + private final UserRepository userRepository; + private final PasswordEncoder passwordEncoder; + private final ValidatorUtil validatorUtil; + private final JwtsProvider jwtProvider; + + public UserService(UserRepository userRepository, + PasswordEncoder passwordEncoder, + ValidatorUtil validatorUtil, + JwtsProvider jwtProvider) { + this.userRepository = userRepository; + this.passwordEncoder = passwordEncoder; + this.validatorUtil = validatorUtil; + this.jwtProvider = jwtProvider; + } + + @Transactional + public User addUser(String login, String password, String passwordConfirm, UserRole role, Long userId){ + if (getUserByLogin(login) != null){ + throw new ValidationException(String.format("User with login %s already exists", login)); + } + if (!Objects.equals(password, passwordConfirm)) { + throw new ValidationException("Passwords not equals"); + } + final User user = new User(login, passwordEncoder.encode(password), role, userId); + validatorUtil.validate(user); + return userRepository.save(user); + } + + @Transactional + public User getUserByLogin(String login){ + return userRepository.findOneByLogin(login); + } + + @Transactional + public List getAllUsers(){ + return userRepository.findAll(); + } + + public UserDetails loadUserByToken(String token) throws UsernameNotFoundException { + if (!jwtProvider.validateToken(token)) { + throw new JwtException("Bad token"); + } + final String userLogin = jwtProvider.getLogin(token); + if (userLogin.isEmpty()) { + throw new JwtException("Token is not contain Login"); + } + return loadUserByUsername(userLogin); + } + + public String loginAndGetToken(UserDTO userDto) { + final User user = getUserByLogin(userDto.getLogin()); + if (user == null) { + throw new UserNotFoundException(userDto.getLogin()); + } + if (!passwordEncoder.matches(userDto.getPassword(), user.getPassword())) { + throw new UserNotFoundException(user.getLogin()); + } + return jwtProvider.generateToken(user.getLogin(), user.getRole().name()); + } + + @Override + public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { + final User userEntity = getUserByLogin(username); + if (userEntity == null) { + throw new UsernameNotFoundException(username); + } + return new CustomUser( + userEntity.getLogin(), userEntity.getPassword(), Collections.singleton(userEntity.getRole()), userEntity.getId(), userEntity.getRole()); + } +} diff --git a/backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/util/error/AdviceController.java b/backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/util/error/AdviceController.java index 2a261cf..3e37134 100644 --- a/backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/util/error/AdviceController.java +++ b/backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/util/error/AdviceController.java @@ -13,6 +13,7 @@ import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestController; +import java.nio.file.AccessDeniedException; import java.util.stream.Collectors; @ControllerAdvice(annotations = RestController.class) @@ -35,6 +36,14 @@ public class AdviceController { return handleException(validationException); } + @ExceptionHandler({ + AccessDeniedException.class + }) + public ResponseEntity handleAccessDeniedException(Throwable e) { + return new ResponseEntity<>(e.getMessage(), HttpStatus.FORBIDDEN); + } + + @ExceptionHandler(Exception.class) public ResponseEntity handleUnknownException(Throwable e) { e.printStackTrace(); diff --git a/backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/util/validation/ValidationException.java b/backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/util/validation/ValidationException.java index 41bbcac..6fcfb85 100644 --- a/backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/util/validation/ValidationException.java +++ b/backend/ipLab/src/main/java/com/example/ipLab/StoreDataBase/util/validation/ValidationException.java @@ -6,4 +6,8 @@ public class ValidationException extends RuntimeException{ public ValidationException(Set errors){ super(String.join("\n", errors)); } + + public ValidationException(String error){ + super(error); + } } diff --git a/backend/ipLab/src/main/java/com/example/ipLab/WebConfiguration.java b/backend/ipLab/src/main/java/com/example/ipLab/WebConfiguration.java index 8db3443..24b259e 100644 --- a/backend/ipLab/src/main/java/com/example/ipLab/WebConfiguration.java +++ b/backend/ipLab/src/main/java/com/example/ipLab/WebConfiguration.java @@ -2,11 +2,18 @@ package com.example.ipLab; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.CorsRegistry; +import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class WebConfiguration implements WebMvcConfigurer { public static final String REST_API = "/api"; + + @Override + public void addViewControllers(ViewControllerRegistry registry) { + WebMvcConfigurer.super.addViewControllers(registry); + registry.addViewController("login"); + } @Override public void addCorsMappings(CorsRegistry registry){ registry.addMapping("/**").allowedMethods("*"); diff --git a/backend/ipLab/src/main/resources/application.properties b/backend/ipLab/src/main/resources/application.properties index da7b0b1..d4ce457 100644 --- a/backend/ipLab/src/main/resources/application.properties +++ b/backend/ipLab/src/main/resources/application.properties @@ -9,3 +9,6 @@ spring.jpa.hibernate.ddl-auto=update spring.h2.console.enabled=true spring.h2.console.settings.trace=false spring.h2.console.settings.web-allow-others=false +jwt.dev-token=my-secret-jwt +jwt.dev=true +jwt.secret = my-secret-jwt diff --git a/backend/ipLab/src/main/resources/static/img/logo.png b/backend/ipLab/src/main/resources/static/img/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..f7c2e6ee02d9d42ebe75e4b482efe87c4bd9f9a6 GIT binary patch literal 9949 zcmd^lcT`i~w(d$m2p|v?6;OJUjz}*Okrs+zXwn3vgA}P6L?SAn(h;Iml_1iBbO8|* z1wjD`V32O1gwRw16589G^E+qUbKe_xyfeoA}X?s3;=NG5)Ked&}sF`ARRif1RL9j0>II}_k(o?J@bGXdBY6Ohgk)Ag+;oB zc!J2tNO|8t|4?_gU{Cp=5bvBNZ9V{m09yaF^_ASk@vFhPw7l7$eU;7OAJWA?tl#0h zq^N=WXeMNKK*{Vq3(MP754Zt*_}HNc2`jC-=DHl3_1d%ShhjBf9-^yNv}*RT;NN(L za(Ev|tU9fVpB^1fm;I6@YhS%&yB@UbbLmzZXVnvq*)28Ua@ciuhJKXgko$b{D zL%=#=t}sG+QrI-c;~bbIuVVXK%-q+<217c{tKwJ|&Qge%zPI|#bW-Ie(VGb=`yC6w z>pwdg^&aYleU84j31#9od4E*cE8I`jy4Wi4luYn#KXuEba9*(n97uqI+5dcG{`o%T zfc>~oAywR_V4iAm02I~EELd$7_nm)uYHdH< zwN}*DL8c6Q5hUosLBivMs@p*(*{W&Z6Hfv|Q6}62QGk1(?l#bRfwWqqGh@%#=HqOO zb+V;(%u(WOB=Ycua0E9D=nu~isrF;5VYbLHf&s_5L8IW-Zs3tPQubl=! z_(gb`OfEvF@4U!i zP^e;x)rS<|frIyj=W=!$#N{sQ^ilNH|7H(>1a0AzD1hNF^{6KEQH*~bsWc-Xf%0D3<`V`0%Bocc02PjKS;*GwEl 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 literal 0 HcmV?d00001 diff --git a/backend/ipLab/src/main/resources/templates/addToStore.html b/backend/ipLab/src/main/resources/templates/addToStore.html index 720e9c1..19d180a 100644 --- a/backend/ipLab/src/main/resources/templates/addToStore.html +++ b/backend/ipLab/src/main/resources/templates/addToStore.html @@ -5,7 +5,7 @@ -
+
diff --git a/backend/ipLab/src/main/resources/templates/customer.html b/backend/ipLab/src/main/resources/templates/customer.html index 16afff1..352bbed 100644 --- a/backend/ipLab/src/main/resources/templates/customer.html +++ b/backend/ipLab/src/main/resources/templates/customer.html @@ -5,7 +5,7 @@ -
+
@@ -17,6 +17,7 @@ # + ID Фамилия Имя Отчество @@ -26,6 +27,7 @@ + diff --git a/backend/ipLab/src/main/resources/templates/default.html b/backend/ipLab/src/main/resources/templates/default.html index e56935f..4f1eb5f 100644 --- a/backend/ipLab/src/main/resources/templates/default.html +++ b/backend/ipLab/src/main/resources/templates/default.html @@ -23,7 +23,7 @@
- * + *
boxStore @@ -31,7 +31,7 @@
diff --git a/backend/ipLab/src/main/resources/templates/index.html b/backend/ipLab/src/main/resources/templates/index.html index 751437c..1e4a266 100644 --- a/backend/ipLab/src/main/resources/templates/index.html +++ b/backend/ipLab/src/main/resources/templates/index.html @@ -6,7 +6,7 @@
-

Добро пожаловать!

+

Добро пожаловать, !

\ No newline at end of file diff --git a/backend/ipLab/src/main/resources/templates/login.html b/backend/ipLab/src/main/resources/templates/login.html new file mode 100644 index 0000000..7b24fe5 --- /dev/null +++ b/backend/ipLab/src/main/resources/templates/login.html @@ -0,0 +1,43 @@ + + + + + +
+
+ Пользователь не найден или пароль указан не верно +
+
+ Выход успешно произведен +
+
+ Пользователь '' успешно создан +
+
+
+
+
+
Авторизация
+ +
+ + +
+
+ + +
+ + +
+
+
+
+ +
+ + \ No newline at end of file diff --git a/backend/ipLab/src/main/resources/templates/order.html b/backend/ipLab/src/main/resources/templates/order.html index 0c14220..7e84c0e 100644 --- a/backend/ipLab/src/main/resources/templates/order.html +++ b/backend/ipLab/src/main/resources/templates/order.html @@ -6,7 +6,7 @@
-
+
Добавить diff --git a/backend/ipLab/src/main/resources/templates/product.html b/backend/ipLab/src/main/resources/templates/product.html index 3211ccb..2b53163 100644 --- a/backend/ipLab/src/main/resources/templates/product.html +++ b/backend/ipLab/src/main/resources/templates/product.html @@ -6,7 +6,7 @@
-
+
Добавить @@ -19,7 +19,7 @@ # Название товара Название магазина - + @@ -27,7 +27,7 @@ - +