From 77a8c9e3ed5e255a9e90361c763f1c780d222996 Mon Sep 17 00:00:00 2001 From: ChabVlad Date: Sun, 22 Sep 2024 00:07:50 +0400 Subject: [PATCH 1/6] done --- pom.xml | 19 ++++++ .../bookstore/config/SecurityConfig.java | 22 ++++++- .../controller/AuthenticationController.java | 9 +++ .../bookstore/controller/BookController.java | 1 + .../dto/user/UserLoginRequestDto.java | 17 ++++++ .../dto/user/UserLoginResponseDto.java | 4 ++ .../security/AuthenticationService.java | 24 ++++++++ .../security/JwtAuthenticationFilter.java | 58 ++++++++++++++++++ .../project/bookstore/security/JwtUtil.java | 60 +++++++++++++++++++ src/main/resources/application.properties | 5 +- src/test/resources/application.properties | 3 + 11 files changed, 219 insertions(+), 3 deletions(-) create mode 100644 src/main/java/project/bookstore/dto/user/UserLoginRequestDto.java create mode 100644 src/main/java/project/bookstore/dto/user/UserLoginResponseDto.java create mode 100644 src/main/java/project/bookstore/security/AuthenticationService.java create mode 100644 src/main/java/project/bookstore/security/JwtAuthenticationFilter.java create mode 100644 src/main/java/project/bookstore/security/JwtUtil.java diff --git a/pom.xml b/pom.xml index 59c144b..0b5b42c 100644 --- a/pom.xml +++ b/pom.xml @@ -31,6 +31,7 @@ checkstyle.xml 0.2.0 1.5.5.Final + 0.12.6 @@ -123,6 +124,24 @@ 2.6.0 + + io.jsonwebtoken + jjwt-api + ${jjwt.version} + + + + io.jsonwebtoken + jjwt-impl + ${jjwt.version} + + + + io.jsonwebtoken + jjwt-jackson + ${jjwt.version} + + diff --git a/src/main/java/project/bookstore/config/SecurityConfig.java b/src/main/java/project/bookstore/config/SecurityConfig.java index 764fe4a..2a88277 100644 --- a/src/main/java/project/bookstore/config/SecurityConfig.java +++ b/src/main/java/project/bookstore/config/SecurityConfig.java @@ -3,20 +3,25 @@ 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.configuration.AuthenticationConfiguration; import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; +import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.core.userdetails.UserDetailsService; 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 project.bookstore.security.JwtAuthenticationFilter; @Configuration @EnableMethodSecurity @RequiredArgsConstructor public class SecurityConfig { private final UserDetailsService userDetailsService; + private final JwtAuthenticationFilter jwtAuthenticationFilter; @Bean public PasswordEncoder passwordEncoder() { @@ -31,8 +36,8 @@ public SecurityFilterChain getSecurityFilterChain(HttpSecurity http) throws Exce .authorizeHttpRequests( auth -> auth .requestMatchers( - HttpMethod.POST, "/auth/**", + "/api/auth/register", "/swagger-ui/**", "/v3/api-docs/**" ) @@ -40,7 +45,20 @@ public SecurityFilterChain getSecurityFilterChain(HttpSecurity http) throws Exce .anyRequest() .authenticated() ) + .addFilterBefore( + jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class + ) + .sessionManagement( + session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS + )) .userDetailsService(userDetailsService) .build(); } + + @Bean + public AuthenticationManager authenticationManager( + AuthenticationConfiguration authenticationConfiguration + ) throws Exception { + return authenticationConfiguration.getAuthenticationManager(); + } } diff --git a/src/main/java/project/bookstore/controller/AuthenticationController.java b/src/main/java/project/bookstore/controller/AuthenticationController.java index 72a2826..71d2ee1 100644 --- a/src/main/java/project/bookstore/controller/AuthenticationController.java +++ b/src/main/java/project/bookstore/controller/AuthenticationController.java @@ -8,9 +8,12 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import project.bookstore.dto.user.UserLoginRequestDto; +import project.bookstore.dto.user.UserLoginResponseDto; import project.bookstore.dto.user.UserRegistrationRequestDto; import project.bookstore.dto.user.UserResponseDto; import project.bookstore.exception.RegistrationException; +import project.bookstore.security.AuthenticationService; import project.bookstore.service.UserService; @Tag(name = "Authentication controller", description = "endpoints for authentication") @@ -19,6 +22,7 @@ @RequestMapping("/auth") public class AuthenticationController { private final UserService userService; + private final AuthenticationService authenticationService; @PostMapping("/register") @Operation( @@ -31,4 +35,9 @@ public UserResponseDto register(@RequestBody @Valid UserRegistrationRequestDto r return userService.register(requestDto); } + + @PostMapping("/login") + public UserLoginResponseDto login(UserLoginRequestDto requestDto) { + return authenticationService.authenticate(requestDto); + } } diff --git a/src/main/java/project/bookstore/controller/BookController.java b/src/main/java/project/bookstore/controller/BookController.java index 68033b3..55f4b77 100644 --- a/src/main/java/project/bookstore/controller/BookController.java +++ b/src/main/java/project/bookstore/controller/BookController.java @@ -30,6 +30,7 @@ public class BookController { private final BookMapper bookMapper; @GetMapping + @PreAuthorize("hasRole('ROLE_USER')") @Operation( summary = "Get all books", description = "Get all books from db") diff --git a/src/main/java/project/bookstore/dto/user/UserLoginRequestDto.java b/src/main/java/project/bookstore/dto/user/UserLoginRequestDto.java new file mode 100644 index 0000000..d07bfda --- /dev/null +++ b/src/main/java/project/bookstore/dto/user/UserLoginRequestDto.java @@ -0,0 +1,17 @@ +package project.bookstore.dto.user; + +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; + +public record UserLoginRequestDto( + @NotBlank + @Size(min = 6, max = 20) + @Email + String email, + @NotBlank + @Size(min = 6, max = 20) + String password +) { + +} diff --git a/src/main/java/project/bookstore/dto/user/UserLoginResponseDto.java b/src/main/java/project/bookstore/dto/user/UserLoginResponseDto.java new file mode 100644 index 0000000..636a4a6 --- /dev/null +++ b/src/main/java/project/bookstore/dto/user/UserLoginResponseDto.java @@ -0,0 +1,4 @@ +package project.bookstore.dto.user; + +public record UserLoginResponseDto(String token) { +} diff --git a/src/main/java/project/bookstore/security/AuthenticationService.java b/src/main/java/project/bookstore/security/AuthenticationService.java new file mode 100644 index 0000000..36ddf54 --- /dev/null +++ b/src/main/java/project/bookstore/security/AuthenticationService.java @@ -0,0 +1,24 @@ +package project.bookstore.security; + +import lombok.RequiredArgsConstructor; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.stereotype.Service; +import project.bookstore.dto.user.UserLoginRequestDto; +import project.bookstore.dto.user.UserLoginResponseDto; + +@RequiredArgsConstructor +@Service +public class AuthenticationService { + private final JwtUtil jwtUtil; + private final AuthenticationManager authenticationManager; + + public UserLoginResponseDto authenticate(UserLoginRequestDto requestDto) { + final Authentication authentication = authenticationManager.authenticate( + new UsernamePasswordAuthenticationToken(requestDto.email(), requestDto.password()) + ); + String token = jwtUtil.generateToken(authentication.getName()); + return new UserLoginResponseDto(token); + } +} diff --git a/src/main/java/project/bookstore/security/JwtAuthenticationFilter.java b/src/main/java/project/bookstore/security/JwtAuthenticationFilter.java new file mode 100644 index 0000000..1df94ab --- /dev/null +++ b/src/main/java/project/bookstore/security/JwtAuthenticationFilter.java @@ -0,0 +1,58 @@ +package project.bookstore.security; + +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import java.io.IOException; +import lombok.RequiredArgsConstructor; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; +import org.springframework.web.filter.OncePerRequestFilter; + +@RequiredArgsConstructor +@Component +public class JwtAuthenticationFilter extends OncePerRequestFilter { + private final JwtUtil jwtUtil; + private final UserDetailsService userDetailsService; + + @Override + protected void doFilterInternal( + HttpServletRequest request, + HttpServletResponse response, + FilterChain filterChain + ) throws ServletException, IOException { + String path = request.getRequestURI(); + if ( + path.startsWith("/api/auth") + || path.startsWith("/api/swagger-ui") + || path.startsWith("/api/v3/api-docs")) { + filterChain.doFilter(request, response); + return; + } + String token = getToken(request); + boolean isTokenValid = jwtUtil.isValidToken(token); + if (token != null && isTokenValid) { + String userName = jwtUtil.getUserName(token); + UserDetails userDetails = userDetailsService.loadUserByUsername(userName); + Authentication auth = new UsernamePasswordAuthenticationToken( + userDetails, null, userDetails.getAuthorities() + ); + SecurityContextHolder.getContext().setAuthentication(auth); + } + filterChain.doFilter(request, response); + } + + private String getToken(HttpServletRequest request) { + String bearerToken = request.getHeader("Authorization"); + if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) { + return bearerToken.substring(7); + } + return null; + } +} diff --git a/src/main/java/project/bookstore/security/JwtUtil.java b/src/main/java/project/bookstore/security/JwtUtil.java new file mode 100644 index 0000000..518f8ff --- /dev/null +++ b/src/main/java/project/bookstore/security/JwtUtil.java @@ -0,0 +1,60 @@ +package project.bookstore.security; + +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jws; +import io.jsonwebtoken.JwtException; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.security.Keys; +import java.nio.charset.StandardCharsets; +import java.util.Date; +import java.util.function.Function; +import javax.crypto.SecretKey; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class JwtUtil { + @Value("${jwt.expiration}") + private long expiration; + private final SecretKey secret; + + private JwtUtil(@Value("${jwt.secret}") String secretString) { + secret = Keys.hmacShaKeyFor(secretString.getBytes(StandardCharsets.UTF_8)); + } + + public String generateToken(String name) { + return Jwts.builder() + .subject(name) + .issuedAt(new Date(System.currentTimeMillis())) + .expiration(new Date(System.currentTimeMillis() + expiration)) + .signWith(secret) + .compact(); + } + + public boolean isValidToken(String token) { + try { + Jws claimsJws = Jwts.parser() + .verifyWith(secret) + .build() + .parseSignedClaims(token); + + return !claimsJws.getPayload().getExpiration().before(new Date()); + } catch (JwtException | IllegalArgumentException e) { + throw new JwtException("Expired or invalid Jwt token", e); + } + } + + public String getUserName(String token) { + return getClaimFromToken(token, Claims::getSubject); + } + + private T getClaimFromToken(String token, Function claimsResolver) { + final Claims claims = Jwts.parser() + .verifyWith(secret) + .build() + .parseSignedClaims(token) + .getPayload(); + + return claimsResolver.apply(claims); + } +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 03ab421..28b750d 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -2,10 +2,13 @@ spring.application.name=BookStore spring.datasource.url=jdbc:mysql://localhost/book_store?serverTimezone=UTC spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver spring.datasource.username=root -spring.datasource.password=pass +spring.datasource.password=!Vladius080197 spring.jpa.hibernate.ddl-auto=validate spring.jpa.show-sql=true spring.jpa.open-in-view=false server.servlet.context-path=/api + +jwt.expiration=1000000 +jwt.secret=qwertyuiopasdfghjklzxcvbnm34567890 diff --git a/src/test/resources/application.properties b/src/test/resources/application.properties index 13790c5..67005ef 100644 --- a/src/test/resources/application.properties +++ b/src/test/resources/application.properties @@ -6,3 +6,6 @@ spring.jpa.database-platform=org.hibernate.dialect.H2Dialect spring.jpa.hibernate.ddl-auto=create-drop spring.jpa.show-sql=true + +jwt.expiration=1000000 +jwt.secret=qwertyuiopasdfghjklzxcvbnm34567890 From c65a2d4a74ddae18c2fc26101be53dc70058747f Mon Sep 17 00:00:00 2001 From: ChabVlad Date: Sun, 22 Sep 2024 00:13:36 +0400 Subject: [PATCH 2/6] done --- src/main/resources/application.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 28b750d..ab32bb5 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -2,7 +2,7 @@ spring.application.name=BookStore spring.datasource.url=jdbc:mysql://localhost/book_store?serverTimezone=UTC spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver spring.datasource.username=root -spring.datasource.password=!Vladius080197 +spring.datasource.password=pass spring.jpa.hibernate.ddl-auto=validate spring.jpa.show-sql=true From 8de7342f1b6588f2e4efac1c178fe3c5ff443ec9 Mon Sep 17 00:00:00 2001 From: ChabVlad Date: Mon, 23 Sep 2024 15:24:39 +0400 Subject: [PATCH 3/6] jwt --- .../project/bookstore/config/SecurityConfig.java | 7 +++---- .../controller/AuthenticationController.java | 2 +- .../bookstore/security/JwtAuthenticationFilter.java | 13 +++++++++---- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/main/java/project/bookstore/config/SecurityConfig.java b/src/main/java/project/bookstore/config/SecurityConfig.java index 2a88277..c451686 100644 --- a/src/main/java/project/bookstore/config/SecurityConfig.java +++ b/src/main/java/project/bookstore/config/SecurityConfig.java @@ -36,10 +36,9 @@ public SecurityFilterChain getSecurityFilterChain(HttpSecurity http) throws Exce .authorizeHttpRequests( auth -> auth .requestMatchers( - "/auth/**", - "/api/auth/register", - "/swagger-ui/**", - "/v3/api-docs/**" + "/api/auth/**", + "/api/swagger-ui/**", + "/api/v3/api-docs/**" ) .permitAll() .anyRequest() diff --git a/src/main/java/project/bookstore/controller/AuthenticationController.java b/src/main/java/project/bookstore/controller/AuthenticationController.java index 71d2ee1..019d537 100644 --- a/src/main/java/project/bookstore/controller/AuthenticationController.java +++ b/src/main/java/project/bookstore/controller/AuthenticationController.java @@ -37,7 +37,7 @@ public UserResponseDto register(@RequestBody @Valid UserRegistrationRequestDto r } @PostMapping("/login") - public UserLoginResponseDto login(UserLoginRequestDto requestDto) { + public UserLoginResponseDto login(@RequestBody @Valid UserLoginRequestDto requestDto) { return authenticationService.authenticate(requestDto); } } diff --git a/src/main/java/project/bookstore/security/JwtAuthenticationFilter.java b/src/main/java/project/bookstore/security/JwtAuthenticationFilter.java index 1df94ab..2666c6b 100644 --- a/src/main/java/project/bookstore/security/JwtAuthenticationFilter.java +++ b/src/main/java/project/bookstore/security/JwtAuthenticationFilter.java @@ -6,6 +6,7 @@ import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpHeaders; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; @@ -18,6 +19,7 @@ @RequiredArgsConstructor @Component public class JwtAuthenticationFilter extends OncePerRequestFilter { + private static final String TOKEN_HEADER = "Bearer "; private final JwtUtil jwtUtil; private final UserDetailsService userDetailsService; @@ -27,7 +29,7 @@ protected void doFilterInternal( HttpServletResponse response, FilterChain filterChain ) throws ServletException, IOException { - String path = request.getRequestURI(); + /*String path = request.getRequestURI(); if ( path.startsWith("/api/auth") || path.startsWith("/api/swagger-ui") @@ -35,6 +37,9 @@ protected void doFilterInternal( filterChain.doFilter(request, response); return; } + + */ + String token = getToken(request); boolean isTokenValid = jwtUtil.isValidToken(token); if (token != null && isTokenValid) { @@ -49,9 +54,9 @@ protected void doFilterInternal( } private String getToken(HttpServletRequest request) { - String bearerToken = request.getHeader("Authorization"); - if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) { - return bearerToken.substring(7); + String bearerToken = request.getHeader(HttpHeaders.AUTHORIZATION); + if (StringUtils.hasText(bearerToken) && bearerToken.startsWith(TOKEN_HEADER)) { + return bearerToken.substring(TOKEN_HEADER.length()); } return null; } From 1720c7a1e26d2cd7c8b2e22bbcbc94aa75041db2 Mon Sep 17 00:00:00 2001 From: ChabVlad Date: Mon, 23 Sep 2024 16:07:14 +0400 Subject: [PATCH 4/6] jwt_done --- .../bookstore/config/SecurityConfig.java | 23 ++++++------- .../security/JwtAuthenticationFilter.java | 34 +++++-------------- .../project/bookstore/security/JwtUtil.java | 20 ++++------- .../changes/02-create-users-table.yaml | 8 ++++- .../changes/06-add-isDeleted-to-users.yaml | 14 -------- .../db/changelog/db.changelog-master.yaml | 2 -- 6 files changed, 33 insertions(+), 68 deletions(-) delete mode 100644 src/main/resources/db/changelog/changes/06-add-isDeleted-to-users.yaml diff --git a/src/main/java/project/bookstore/config/SecurityConfig.java b/src/main/java/project/bookstore/config/SecurityConfig.java index c451686..a36b31e 100644 --- a/src/main/java/project/bookstore/config/SecurityConfig.java +++ b/src/main/java/project/bookstore/config/SecurityConfig.java @@ -1,5 +1,7 @@ package project.bookstore.config; +import static org.springframework.security.web.util.matcher.AntPathRequestMatcher.antMatcher; + import lombok.RequiredArgsConstructor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -20,7 +22,7 @@ @EnableMethodSecurity @RequiredArgsConstructor public class SecurityConfig { - private final UserDetailsService userDetailsService; + private final UserDetailsService service; private final JwtAuthenticationFilter jwtAuthenticationFilter; @Bean @@ -29,28 +31,25 @@ public PasswordEncoder passwordEncoder() { } @Bean - public SecurityFilterChain getSecurityFilterChain(HttpSecurity http) throws Exception { + public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { return http .cors(AbstractHttpConfigurer::disable) .csrf(AbstractHttpConfigurer::disable) .authorizeHttpRequests( auth -> auth .requestMatchers( - "/api/auth/**", - "/api/swagger-ui/**", - "/api/v3/api-docs/**" - ) + antMatcher("/auth/**"), + antMatcher("/swagger-ui/**"), + antMatcher("/v3/api-docs/**")) .permitAll() .anyRequest() .authenticated() ) - .addFilterBefore( - jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class - ) .sessionManagement( - session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS - )) - .userDetailsService(userDetailsService) + s -> s.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) + .addFilterBefore(jwtAuthenticationFilter, + UsernamePasswordAuthenticationFilter.class) + .userDetailsService(service) .build(); } diff --git a/src/main/java/project/bookstore/security/JwtAuthenticationFilter.java b/src/main/java/project/bookstore/security/JwtAuthenticationFilter.java index 2666c6b..1a1bdc3 100644 --- a/src/main/java/project/bookstore/security/JwtAuthenticationFilter.java +++ b/src/main/java/project/bookstore/security/JwtAuthenticationFilter.java @@ -21,7 +21,7 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter { private static final String TOKEN_HEADER = "Bearer "; private final JwtUtil jwtUtil; - private final UserDetailsService userDetailsService; + private final UserDetailsService service; @Override protected void doFilterInternal( @@ -29,35 +29,19 @@ protected void doFilterInternal( HttpServletResponse response, FilterChain filterChain ) throws ServletException, IOException { - /*String path = request.getRequestURI(); - if ( - path.startsWith("/api/auth") - || path.startsWith("/api/swagger-ui") - || path.startsWith("/api/v3/api-docs")) { - filterChain.doFilter(request, response); - return; - } - - */ - String token = getToken(request); - boolean isTokenValid = jwtUtil.isValidToken(token); - if (token != null && isTokenValid) { - String userName = jwtUtil.getUserName(token); - UserDetails userDetails = userDetailsService.loadUserByUsername(userName); - Authentication auth = new UsernamePasswordAuthenticationToken( - userDetails, null, userDetails.getAuthorities() - ); - SecurityContextHolder.getContext().setAuthentication(auth); + if (token != null && jwtUtil.isValidToken(token)) { + UserDetails userDetails = service.loadUserByUsername(jwtUtil.getUserName(token)); + Authentication authentication = new UsernamePasswordAuthenticationToken( + userDetails, null, userDetails.getAuthorities()); + SecurityContextHolder.getContext().setAuthentication(authentication); } filterChain.doFilter(request, response); } private String getToken(HttpServletRequest request) { - String bearerToken = request.getHeader(HttpHeaders.AUTHORIZATION); - if (StringUtils.hasText(bearerToken) && bearerToken.startsWith(TOKEN_HEADER)) { - return bearerToken.substring(TOKEN_HEADER.length()); - } - return null; + String token = request.getHeader(HttpHeaders.AUTHORIZATION); + return (StringUtils.hasText(token) && token.startsWith(TOKEN_HEADER)) + ? token.substring(TOKEN_HEADER.length()) : null; } } diff --git a/src/main/java/project/bookstore/security/JwtUtil.java b/src/main/java/project/bookstore/security/JwtUtil.java index 518f8ff..b571dd8 100644 --- a/src/main/java/project/bookstore/security/JwtUtil.java +++ b/src/main/java/project/bookstore/security/JwtUtil.java @@ -1,7 +1,6 @@ package project.bookstore.security; import io.jsonwebtoken.Claims; -import io.jsonwebtoken.Jws; import io.jsonwebtoken.JwtException; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.security.Keys; @@ -18,14 +17,13 @@ public class JwtUtil { private long expiration; private final SecretKey secret; - private JwtUtil(@Value("${jwt.secret}") String secretString) { + public JwtUtil(@Value(value = "${jwt.secret}") String secretString) { secret = Keys.hmacShaKeyFor(secretString.getBytes(StandardCharsets.UTF_8)); } - public String generateToken(String name) { + public String generateToken(String username) { return Jwts.builder() - .subject(name) - .issuedAt(new Date(System.currentTimeMillis())) + .subject(username) .expiration(new Date(System.currentTimeMillis() + expiration)) .signWith(secret) .compact(); @@ -33,14 +31,9 @@ public String generateToken(String name) { public boolean isValidToken(String token) { try { - Jws claimsJws = Jwts.parser() - .verifyWith(secret) - .build() - .parseSignedClaims(token); - - return !claimsJws.getPayload().getExpiration().before(new Date()); + return !getClaimFromToken(token, Claims::getExpiration).before(new Date()); } catch (JwtException | IllegalArgumentException e) { - throw new JwtException("Expired or invalid Jwt token", e); + throw new JwtException("Expired or invalid JWT token", e); } } @@ -50,11 +43,10 @@ public String getUserName(String token) { private T getClaimFromToken(String token, Function claimsResolver) { final Claims claims = Jwts.parser() - .verifyWith(secret) + .verifyWith((SecretKey) secret) .build() .parseSignedClaims(token) .getPayload(); - return claimsResolver.apply(claims); } } diff --git a/src/main/resources/db/changelog/changes/02-create-users-table.yaml b/src/main/resources/db/changelog/changes/02-create-users-table.yaml index 00b0b96..3b45732 100644 --- a/src/main/resources/db/changelog/changes/02-create-users-table.yaml +++ b/src/main/resources/db/changelog/changes/02-create-users-table.yaml @@ -36,4 +36,10 @@ databaseChangeLog: nullable: false - column: name: shipping_address - type: varchar(255) \ No newline at end of file + type: varchar(255) + - column: + name: is_deleted + type: tinyint + defaultValueBoolean: false + constraints: + nullable: false diff --git a/src/main/resources/db/changelog/changes/06-add-isDeleted-to-users.yaml b/src/main/resources/db/changelog/changes/06-add-isDeleted-to-users.yaml deleted file mode 100644 index dcab0c6..0000000 --- a/src/main/resources/db/changelog/changes/06-add-isDeleted-to-users.yaml +++ /dev/null @@ -1,14 +0,0 @@ -databaseChangeLog: - - changeSet: - id: add-isDeleted-to-users - author: vlad - changes: - - addColumn: - tableName: users - columns: - - column: - name: is_deleted - type: tinyint - defaultValueBoolean: false - constraints: - nullable: false diff --git a/src/main/resources/db/changelog/db.changelog-master.yaml b/src/main/resources/db/changelog/db.changelog-master.yaml index 19df5dd..ec80400 100644 --- a/src/main/resources/db/changelog/db.changelog-master.yaml +++ b/src/main/resources/db/changelog/db.changelog-master.yaml @@ -9,5 +9,3 @@ databaseChangeLog: file: db/changelog/changes/04-create-users-roles-table.yaml - include: file: db/changelog/changes/05-insert-users-to-db.yaml - - include: - file: db/changelog/changes/06-add-isDeleted-to-users.yaml From 6b91e31526075ba250dfe14db104932e74bce940 Mon Sep 17 00:00:00 2001 From: ChabVlad Date: Mon, 23 Sep 2024 16:17:19 +0400 Subject: [PATCH 5/6] jwt_hw --- src/main/java/project/bookstore/config/SecurityConfig.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/project/bookstore/config/SecurityConfig.java b/src/main/java/project/bookstore/config/SecurityConfig.java index a0c694d..222f6c6 100644 --- a/src/main/java/project/bookstore/config/SecurityConfig.java +++ b/src/main/java/project/bookstore/config/SecurityConfig.java @@ -40,7 +40,7 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Excepti .requestMatchers( antMatcher("/auth/**"), antMatcher("/swagger-ui/**"), - antMatcher("/v3/api-docs/**")) + antMatcher("/v3/api-docs/**") ) .permitAll() .anyRequest() From 6de4092e8d1ca8f3472e9e9ffe86ddfb988998ba Mon Sep 17 00:00:00 2001 From: ChabVlad Date: Mon, 23 Sep 2024 18:25:09 +0400 Subject: [PATCH 6/6] jwt_hw swagger added --- .../bookstore/controller/AuthenticationController.java | 4 ++++ src/main/java/project/bookstore/model/Book.java | 7 ------- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/main/java/project/bookstore/controller/AuthenticationController.java b/src/main/java/project/bookstore/controller/AuthenticationController.java index 019d537..6a802bc 100644 --- a/src/main/java/project/bookstore/controller/AuthenticationController.java +++ b/src/main/java/project/bookstore/controller/AuthenticationController.java @@ -37,6 +37,10 @@ public UserResponseDto register(@RequestBody @Valid UserRegistrationRequestDto r } @PostMapping("/login") + @Operation( + summary = "login user", + description = "login user by fields: email, password" + ) public UserLoginResponseDto login(@RequestBody @Valid UserLoginRequestDto requestDto) { return authenticationService.authenticate(requestDto); } diff --git a/src/main/java/project/bookstore/model/Book.java b/src/main/java/project/bookstore/model/Book.java index eada0bd..c1f81c2 100644 --- a/src/main/java/project/bookstore/model/Book.java +++ b/src/main/java/project/bookstore/model/Book.java @@ -22,23 +22,16 @@ public class Book { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @Column(nullable = false) private String title; - @Column(nullable = false) private String author; - @Column(unique = true, nullable = false) private String isbn; - @Column(nullable = false) private BigDecimal price; - private String description; - private String coverImage; - @Column(nullable = false, columnDefinition = "TINYINT(1)") private boolean isDeleted = false; }