From c17d3b8c9b7aa6c28a01ff8668fa749b008ffae9 Mon Sep 17 00:00:00 2001 From: Ramazan Sakin Date: Wed, 27 Jul 2022 06:19:53 +0300 Subject: [PATCH 01/13] feat: lombok adaptation & refactoring --- pom.xml | 141 ++++++------ .../SpringBootSecurityJwtApplication.java | 8 +- .../springjwt/controllers/AuthController.java | 201 +++++++++--------- .../springjwt/controllers/TestController.java | 39 ++-- .../com/bezkoder/springjwt/models/ERole.java | 8 +- .../com/bezkoder/springjwt/models/Role.java | 49 ++--- .../com/bezkoder/springjwt/models/User.java | 129 +++++------ .../payload/request/LoginRequest.java | 26 +-- .../payload/request/SignupRequest.java | 56 ++--- .../payload/response/JwtResponse.java | 75 ++----- .../payload/response/MessageResponse.java | 17 +- .../springjwt/repository/RoleRepository.java | 9 +- .../springjwt/repository/UserRepository.java | 11 +- .../springjwt/security/WebSecurityConfig.java | 77 ++++--- .../security/jwt/AuthEntryPointJwt.java | 6 +- .../security/jwt/AuthTokenFilter.java | 90 ++++---- .../springjwt/security/jwt/JwtUtils.java | 95 +++++---- .../security/services/UserDetailsImpl.java | 176 +++++++-------- .../services/UserDetailsServiceImpl.java | 26 +-- 19 files changed, 549 insertions(+), 690 deletions(-) diff --git a/pom.xml b/pom.xml index eed808f..18639fc 100644 --- a/pom.xml +++ b/pom.xml @@ -1,77 +1,90 @@ - 4.0.0 - - org.springframework.boot - spring-boot-starter-parent - 2.6.1 - - - com.bezkoder - spring-boot-security-jwt - 0.0.1-SNAPSHOT - spring-boot-security-jwt - Demo project for Spring Boot Security - JWT + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.6.1 + + + com.bezkoder + spring-boot-security-jwt + 0.0.1-SNAPSHOT + spring-boot-security-jwt + Demo project for Spring Boot Security - JWT - - 1.8 - + + 1.8 + - - - org.springframework.boot - spring-boot-starter-data-jpa - + + + org.springframework.boot + spring-boot-starter-data-jpa + - - org.springframework.boot - spring-boot-starter-security - - - - org.springframework.boot - spring-boot-starter-validation - + + org.springframework.boot + spring-boot-starter-security + - - org.springframework.boot - spring-boot-starter-web - + + org.springframework.boot + spring-boot-starter-validation + - - mysql - mysql-connector-java - runtime - + + org.springframework.boot + spring-boot-starter-web + - - io.jsonwebtoken - jjwt - 0.9.1 - + + mysql + mysql-connector-java + runtime + - - org.springframework.boot - spring-boot-starter-test - test - + + io.jsonwebtoken + jjwt + 0.9.1 + + + org.projectlombok + lombok + 1.18.24 + - - org.springframework.security - spring-security-test - test - - + + org.springframework.boot + spring-boot-starter-test + test + - - - - org.springframework.boot - spring-boot-maven-plugin - - - + + org.springframework.security + spring-security-test + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + org.projectlombok + lombok + + + + + + diff --git a/src/main/java/com/bezkoder/springjwt/SpringBootSecurityJwtApplication.java b/src/main/java/com/bezkoder/springjwt/SpringBootSecurityJwtApplication.java index c723518..4c6d3b1 100644 --- a/src/main/java/com/bezkoder/springjwt/SpringBootSecurityJwtApplication.java +++ b/src/main/java/com/bezkoder/springjwt/SpringBootSecurityJwtApplication.java @@ -6,8 +6,8 @@ @SpringBootApplication public class SpringBootSecurityJwtApplication { - public static void main(String[] args) { - SpringApplication.run(SpringBootSecurityJwtApplication.class, args); - } + public static void main(String[] args) { + SpringApplication.run(SpringBootSecurityJwtApplication.class, args); + } -} +} \ No newline at end of file diff --git a/src/main/java/com/bezkoder/springjwt/controllers/AuthController.java b/src/main/java/com/bezkoder/springjwt/controllers/AuthController.java index 4287ba1..9eb1c46 100644 --- a/src/main/java/com/bezkoder/springjwt/controllers/AuthController.java +++ b/src/main/java/com/bezkoder/springjwt/controllers/AuthController.java @@ -1,17 +1,22 @@ package com.bezkoder.springjwt.controllers; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; - -import javax.validation.Valid; - -import org.springframework.beans.factory.annotation.Autowired; +import com.bezkoder.springjwt.models.ERole; +import com.bezkoder.springjwt.models.Role; +import com.bezkoder.springjwt.models.User; +import com.bezkoder.springjwt.payload.request.LoginRequest; +import com.bezkoder.springjwt.payload.request.SignupRequest; +import com.bezkoder.springjwt.payload.response.JwtResponse; +import com.bezkoder.springjwt.payload.response.MessageResponse; +import com.bezkoder.springjwt.repository.RoleRepository; +import com.bezkoder.springjwt.repository.UserRepository; +import com.bezkoder.springjwt.security.jwt.JwtUtils; +import com.bezkoder.springjwt.security.services.UserDetailsImpl; +import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; +import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.web.bind.annotation.CrossOrigin; @@ -20,110 +25,100 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import com.bezkoder.springjwt.models.ERole; -import com.bezkoder.springjwt.models.Role; -import com.bezkoder.springjwt.models.User; -import com.bezkoder.springjwt.payload.request.LoginRequest; -import com.bezkoder.springjwt.payload.request.SignupRequest; -import com.bezkoder.springjwt.payload.response.JwtResponse; -import com.bezkoder.springjwt.payload.response.MessageResponse; -import com.bezkoder.springjwt.repository.RoleRepository; -import com.bezkoder.springjwt.repository.UserRepository; -import com.bezkoder.springjwt.security.jwt.JwtUtils; -import com.bezkoder.springjwt.security.services.UserDetailsImpl; +import javax.validation.Valid; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; @CrossOrigin(origins = "*", maxAge = 3600) @RestController +@RequiredArgsConstructor @RequestMapping("/api/auth") public class AuthController { - @Autowired - AuthenticationManager authenticationManager; - - @Autowired - UserRepository userRepository; - - @Autowired - RoleRepository roleRepository; - - @Autowired - PasswordEncoder encoder; - - @Autowired - JwtUtils jwtUtils; - - @PostMapping("/signin") - public ResponseEntity authenticateUser(@Valid @RequestBody LoginRequest loginRequest) { - - Authentication authentication = authenticationManager.authenticate( - new UsernamePasswordAuthenticationToken(loginRequest.getUsername(), loginRequest.getPassword())); - - SecurityContextHolder.getContext().setAuthentication(authentication); - String jwt = jwtUtils.generateJwtToken(authentication); - - UserDetailsImpl userDetails = (UserDetailsImpl) authentication.getPrincipal(); - List roles = userDetails.getAuthorities().stream() - .map(item -> item.getAuthority()) - .collect(Collectors.toList()); - - return ResponseEntity.ok(new JwtResponse(jwt, - userDetails.getId(), - userDetails.getUsername(), - userDetails.getEmail(), - roles)); - } - - @PostMapping("/signup") - public ResponseEntity registerUser(@Valid @RequestBody SignupRequest signUpRequest) { - if (userRepository.existsByUsername(signUpRequest.getUsername())) { - return ResponseEntity - .badRequest() - .body(new MessageResponse("Error: Username is already taken!")); - } - if (userRepository.existsByEmail(signUpRequest.getEmail())) { - return ResponseEntity - .badRequest() - .body(new MessageResponse("Error: Email is already in use!")); + private final AuthenticationManager authenticationManager; + + private final UserRepository userRepository; + + private final RoleRepository roleRepository; + + private final PasswordEncoder encoder; + + private final JwtUtils jwtUtils; + + @PostMapping("/signin") + public ResponseEntity authenticateUser(@Valid @RequestBody LoginRequest loginRequest) { + + Authentication authentication = authenticationManager.authenticate( + new UsernamePasswordAuthenticationToken(loginRequest.getUsername(), loginRequest.getPassword())); + + SecurityContextHolder.getContext().setAuthentication(authentication); + String jwt = jwtUtils.generateJwtToken(authentication); + + UserDetailsImpl userDetails = (UserDetailsImpl) authentication.getPrincipal(); + List roles = userDetails.getAuthorities().stream() + .map(GrantedAuthority::getAuthority) + .collect(Collectors.toList()); + + return ResponseEntity.ok(new JwtResponse(jwt, + userDetails.getId(), + userDetails.getUsername(), + userDetails.getEmail(), + roles)); } - // Create new user's account - User user = new User(signUpRequest.getUsername(), - signUpRequest.getEmail(), - encoder.encode(signUpRequest.getPassword())); - - Set strRoles = signUpRequest.getRole(); - Set roles = new HashSet<>(); - - if (strRoles == null) { - Role userRole = roleRepository.findByName(ERole.ROLE_USER) - .orElseThrow(() -> new RuntimeException("Error: Role is not found.")); - roles.add(userRole); - } else { - strRoles.forEach(role -> { - switch (role) { - case "admin": - Role adminRole = roleRepository.findByName(ERole.ROLE_ADMIN) - .orElseThrow(() -> new RuntimeException("Error: Role is not found.")); - roles.add(adminRole); - - break; - case "mod": - Role modRole = roleRepository.findByName(ERole.ROLE_MODERATOR) - .orElseThrow(() -> new RuntimeException("Error: Role is not found.")); - roles.add(modRole); - - break; - default: - Role userRole = roleRepository.findByName(ERole.ROLE_USER) - .orElseThrow(() -> new RuntimeException("Error: Role is not found.")); - roles.add(userRole); + @PostMapping("/signup") + public ResponseEntity registerUser(@Valid @RequestBody SignupRequest signUpRequest) { + if (userRepository.existsByUsername(signUpRequest.getUsername())) { + return ResponseEntity + .badRequest() + .body(new MessageResponse("Error: Username is already taken!")); + } + + if (userRepository.existsByEmail(signUpRequest.getEmail())) { + return ResponseEntity + .badRequest() + .body(new MessageResponse("Error: Email is already in use!")); } - }); - } - user.setRoles(roles); - userRepository.save(user); + // Create new user's account + User user = new User(signUpRequest.getUsername(), + signUpRequest.getEmail(), + encoder.encode(signUpRequest.getPassword())); + + Set strRoles = signUpRequest.getRoles(); + Set roles = new HashSet<>(); + + if (strRoles == null) { + Role userRole = roleRepository.findByName(ERole.ROLE_USER) + .orElseThrow(() -> new RuntimeException("Error: Role is not found.")); + roles.add(userRole); + } else { + strRoles.forEach(role -> { + switch (role) { + case "admin": + Role adminRole = roleRepository.findByName(ERole.ROLE_ADMIN) + .orElseThrow(() -> new RuntimeException("Error: Role is not found.")); + roles.add(adminRole); + + break; + case "mod": + Role modRole = roleRepository.findByName(ERole.ROLE_MODERATOR) + .orElseThrow(() -> new RuntimeException("Error: Role is not found.")); + roles.add(modRole); + + break; + default: + Role userRole = roleRepository.findByName(ERole.ROLE_USER) + .orElseThrow(() -> new RuntimeException("Error: Role is not found.")); + roles.add(userRole); + } + }); + } - return ResponseEntity.ok(new MessageResponse("User registered successfully!")); - } + user.setRoles(roles); + userRepository.save(user); + return ResponseEntity.ok(new MessageResponse("User registered successfully!")); + } } diff --git a/src/main/java/com/bezkoder/springjwt/controllers/TestController.java b/src/main/java/com/bezkoder/springjwt/controllers/TestController.java index e03b5cb..e018c3a 100644 --- a/src/main/java/com/bezkoder/springjwt/controllers/TestController.java +++ b/src/main/java/com/bezkoder/springjwt/controllers/TestController.java @@ -10,26 +10,27 @@ @RestController @RequestMapping("/api/test") public class TestController { - @GetMapping("/all") - public String allAccess() { - return "Public Content."; - } - @GetMapping("/user") - @PreAuthorize("hasRole('USER') or hasRole('MODERATOR') or hasRole('ADMIN')") - public String userAccess() { - return "User Content."; - } + @GetMapping("/all") + public String allAccess() { + return "Public Content."; + } - @GetMapping("/mod") - @PreAuthorize("hasRole('MODERATOR')") - public String moderatorAccess() { - return "Moderator Board."; - } + @GetMapping("/user") + @PreAuthorize("hasRole('USER') or hasRole('MODERATOR') or hasRole('ADMIN')") + public String userAccess() { + return "User Content."; + } - @GetMapping("/admin") - @PreAuthorize("hasRole('ADMIN')") - public String adminAccess() { - return "Admin Board."; - } + @GetMapping("/mod") + @PreAuthorize("hasRole('MODERATOR')") + public String moderatorAccess() { + return "Moderator Board."; + } + + @GetMapping("/admin") + @PreAuthorize("hasRole('ADMIN')") + public String adminAccess() { + return "Admin Board."; + } } diff --git a/src/main/java/com/bezkoder/springjwt/models/ERole.java b/src/main/java/com/bezkoder/springjwt/models/ERole.java index a113c68..8c365de 100644 --- a/src/main/java/com/bezkoder/springjwt/models/ERole.java +++ b/src/main/java/com/bezkoder/springjwt/models/ERole.java @@ -1,7 +1,7 @@ package com.bezkoder.springjwt.models; public enum ERole { - ROLE_USER, - ROLE_MODERATOR, - ROLE_ADMIN -} + ROLE_USER, + ROLE_MODERATOR, + ROLE_ADMIN +} \ No newline at end of file diff --git a/src/main/java/com/bezkoder/springjwt/models/Role.java b/src/main/java/com/bezkoder/springjwt/models/Role.java index abf816e..873889b 100644 --- a/src/main/java/com/bezkoder/springjwt/models/Role.java +++ b/src/main/java/com/bezkoder/springjwt/models/Role.java @@ -1,39 +1,26 @@ package com.bezkoder.springjwt.models; -import javax.persistence.*; - +import lombok.Data; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; + +@Data @Entity @Table(name = "roles") public class Role { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Integer id; - - @Enumerated(EnumType.STRING) - @Column(length = 20) - private ERole name; - - public Role() { - - } - - public Role(ERole name) { - this.name = name; - } - - public Integer getId() { - return id; - } - - public void setId(Integer id) { - this.id = id; - } + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Integer id; - public ERole getName() { - return name; - } + @Enumerated(EnumType.STRING) + @Column(length = 20) + private ERole name; - public void setName(ERole name) { - this.name = name; - } } \ No newline at end of file diff --git a/src/main/java/com/bezkoder/springjwt/models/User.java b/src/main/java/com/bezkoder/springjwt/models/User.java index 9f03ab1..8bd273e 100644 --- a/src/main/java/com/bezkoder/springjwt/models/User.java +++ b/src/main/java/com/bezkoder/springjwt/models/User.java @@ -1,89 +1,60 @@ package com.bezkoder.springjwt.models; -import java.util.HashSet; -import java.util.Set; - -import javax.persistence.*; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.JoinTable; +import javax.persistence.ManyToMany; +import javax.persistence.Table; +import javax.persistence.UniqueConstraint; import javax.validation.constraints.Email; import javax.validation.constraints.NotBlank; import javax.validation.constraints.Size; +import java.util.HashSet; +import java.util.Set; +@Data +@NoArgsConstructor @Entity -@Table(name = "users", - uniqueConstraints = { - @UniqueConstraint(columnNames = "username"), - @UniqueConstraint(columnNames = "email") - }) +@Table(name = "users", + uniqueConstraints = { + @UniqueConstraint(columnNames = "username"), + @UniqueConstraint(columnNames = "email") + }) public class User { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - @NotBlank - @Size(max = 20) - private String username; - - @NotBlank - @Size(max = 50) - @Email - private String email; - - @NotBlank - @Size(max = 120) - private String password; - - @ManyToMany(fetch = FetchType.LAZY) - @JoinTable( name = "user_roles", - joinColumns = @JoinColumn(name = "user_id"), - inverseJoinColumns = @JoinColumn(name = "role_id")) - private Set roles = new HashSet<>(); - - public User() { - } - - public User(String username, String email, String password) { - this.username = username; - this.email = email; - this.password = password; - } - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public String getUsername() { - return username; - } - - public void setUsername(String username) { - this.username = username; - } - - public String getEmail() { - return email; - } - - public void setEmail(String email) { - this.email = email; - } - - public String getPassword() { - return password; - } - - public void setPassword(String password) { - this.password = password; - } - - public Set getRoles() { - return roles; - } + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @NotBlank + @Size(max = 20) + private String username; + + @NotBlank + @Size(max = 50) + @Email + private String email; + + @NotBlank + @Size(max = 120) + private String password; + + @ManyToMany(fetch = FetchType.LAZY) + @JoinTable(name = "user_roles", + joinColumns = @JoinColumn(name = "user_id"), + inverseJoinColumns = @JoinColumn(name = "role_id")) + private Set roles = new HashSet<>(); + + public User(String username, String email, String password) { + this.username = username; + this.email = email; + this.password = password; + } - public void setRoles(Set roles) { - this.roles = roles; - } } diff --git a/src/main/java/com/bezkoder/springjwt/payload/request/LoginRequest.java b/src/main/java/com/bezkoder/springjwt/payload/request/LoginRequest.java index 8b6bedf..5366504 100644 --- a/src/main/java/com/bezkoder/springjwt/payload/request/LoginRequest.java +++ b/src/main/java/com/bezkoder/springjwt/payload/request/LoginRequest.java @@ -1,27 +1,15 @@ package com.bezkoder.springjwt.payload.request; +import lombok.Value; + import javax.validation.constraints.NotBlank; +@Value public class LoginRequest { - @NotBlank - private String username; - - @NotBlank - private String password; - - public String getUsername() { - return username; - } - - public void setUsername(String username) { - this.username = username; - } + @NotBlank + String username; - public String getPassword() { - return password; - } + @NotBlank + String password; - public void setPassword(String password) { - this.password = password; - } } diff --git a/src/main/java/com/bezkoder/springjwt/payload/request/SignupRequest.java b/src/main/java/com/bezkoder/springjwt/payload/request/SignupRequest.java index 899f199..68d0aa3 100644 --- a/src/main/java/com/bezkoder/springjwt/payload/request/SignupRequest.java +++ b/src/main/java/com/bezkoder/springjwt/payload/request/SignupRequest.java @@ -1,54 +1,24 @@ package com.bezkoder.springjwt.payload.request; -import java.util.Set; +import lombok.Value; -import javax.validation.constraints.*; +import javax.validation.constraints.Email; +import javax.validation.constraints.Size; +import java.util.Set; +@Value public class SignupRequest { - @NotBlank - @Size(min = 3, max = 20) - private String username; - - @NotBlank - @Size(max = 50) - @Email - private String email; - - private Set role; - - @NotBlank - @Size(min = 6, max = 40) - private String password; - - public String getUsername() { - return username; - } - - public void setUsername(String username) { - this.username = username; - } - - public String getEmail() { - return email; - } - public void setEmail(String email) { - this.email = email; - } + @Size(min = 3, max = 20) + String username; - public String getPassword() { - return password; - } + @Size(max = 50) + @Email + String email; - public void setPassword(String password) { - this.password = password; - } + Set roles; - public Set getRole() { - return this.role; - } + @Size(min = 6, max = 40) + String password; - public void setRole(Set role) { - this.role = role; - } } diff --git a/src/main/java/com/bezkoder/springjwt/payload/response/JwtResponse.java b/src/main/java/com/bezkoder/springjwt/payload/response/JwtResponse.java index ac387f0..4885b32 100644 --- a/src/main/java/com/bezkoder/springjwt/payload/response/JwtResponse.java +++ b/src/main/java/com/bezkoder/springjwt/payload/response/JwtResponse.java @@ -1,64 +1,23 @@ package com.bezkoder.springjwt.payload.response; +import lombok.Data; + import java.util.List; +@Data public class JwtResponse { - private String token; - private String type = "Bearer"; - private Long id; - private String username; - private String email; - private List roles; - - public JwtResponse(String accessToken, Long id, String username, String email, List roles) { - this.token = accessToken; - this.id = id; - this.username = username; - this.email = email; - this.roles = roles; - } - - public String getAccessToken() { - return token; - } - - public void setAccessToken(String accessToken) { - this.token = accessToken; - } - - public String getTokenType() { - return type; - } - - public void setTokenType(String tokenType) { - this.type = tokenType; - } - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public String getEmail() { - return email; - } - - public void setEmail(String email) { - this.email = email; - } - - public String getUsername() { - return username; - } - - public void setUsername(String username) { - this.username = username; - } - - public List getRoles() { - return roles; - } + private String token; + private String type = "Bearer"; + private Long id; + private String username; + private String email; + private List roles; + + public JwtResponse(String accessToken, Long id, String username, String email, List roles) { + this.token = accessToken; + this.id = id; + this.username = username; + this.email = email; + this.roles = roles; + } } diff --git a/src/main/java/com/bezkoder/springjwt/payload/response/MessageResponse.java b/src/main/java/com/bezkoder/springjwt/payload/response/MessageResponse.java index 068e179..864cee8 100644 --- a/src/main/java/com/bezkoder/springjwt/payload/response/MessageResponse.java +++ b/src/main/java/com/bezkoder/springjwt/payload/response/MessageResponse.java @@ -1,17 +1,8 @@ package com.bezkoder.springjwt.payload.response; -public class MessageResponse { - private String message; - - public MessageResponse(String message) { - this.message = message; - } +import lombok.Data; - public String getMessage() { - return message; - } - - public void setMessage(String message) { - this.message = message; - } +@Data +public class MessageResponse { + private final String message; } diff --git a/src/main/java/com/bezkoder/springjwt/repository/RoleRepository.java b/src/main/java/com/bezkoder/springjwt/repository/RoleRepository.java index a1882d0..e36e6ba 100644 --- a/src/main/java/com/bezkoder/springjwt/repository/RoleRepository.java +++ b/src/main/java/com/bezkoder/springjwt/repository/RoleRepository.java @@ -1,14 +1,13 @@ package com.bezkoder.springjwt.repository; -import java.util.Optional; - +import com.bezkoder.springjwt.models.ERole; +import com.bezkoder.springjwt.models.Role; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; -import com.bezkoder.springjwt.models.ERole; -import com.bezkoder.springjwt.models.Role; +import java.util.Optional; @Repository public interface RoleRepository extends JpaRepository { - Optional findByName(ERole name); + Optional findByName(ERole name); } diff --git a/src/main/java/com/bezkoder/springjwt/repository/UserRepository.java b/src/main/java/com/bezkoder/springjwt/repository/UserRepository.java index d48a98c..fcfbb98 100644 --- a/src/main/java/com/bezkoder/springjwt/repository/UserRepository.java +++ b/src/main/java/com/bezkoder/springjwt/repository/UserRepository.java @@ -1,17 +1,16 @@ package com.bezkoder.springjwt.repository; -import java.util.Optional; - +import com.bezkoder.springjwt.models.User; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; -import com.bezkoder.springjwt.models.User; +import java.util.Optional; @Repository public interface UserRepository extends JpaRepository { - Optional findByUsername(String username); + Optional findByUsername(String username); - Boolean existsByUsername(String username); + Boolean existsByUsername(String username); - Boolean existsByEmail(String email); + Boolean existsByEmail(String email); } diff --git a/src/main/java/com/bezkoder/springjwt/security/WebSecurityConfig.java b/src/main/java/com/bezkoder/springjwt/security/WebSecurityConfig.java index b73080d..b07555d 100644 --- a/src/main/java/com/bezkoder/springjwt/security/WebSecurityConfig.java +++ b/src/main/java/com/bezkoder/springjwt/security/WebSecurityConfig.java @@ -1,6 +1,9 @@ package com.bezkoder.springjwt.security; -import org.springframework.beans.factory.annotation.Autowired; +import com.bezkoder.springjwt.security.jwt.AuthEntryPointJwt; +import com.bezkoder.springjwt.security.jwt.AuthTokenFilter; +import com.bezkoder.springjwt.security.services.UserDetailsServiceImpl; +import lombok.RequiredArgsConstructor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.AuthenticationManager; @@ -14,53 +17,49 @@ import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; -import com.bezkoder.springjwt.security.jwt.AuthEntryPointJwt; -import com.bezkoder.springjwt.security.jwt.AuthTokenFilter; -import com.bezkoder.springjwt.security.services.UserDetailsServiceImpl; - +@RequiredArgsConstructor @Configuration @EnableWebSecurity @EnableGlobalMethodSecurity( - // securedEnabled = true, - // jsr250Enabled = true, - prePostEnabled = true) + // securedEnabled = true, + // jsr250Enabled = true, + prePostEnabled = true) public class WebSecurityConfig extends WebSecurityConfigurerAdapter { - @Autowired - UserDetailsServiceImpl userDetailsService; - @Autowired - private AuthEntryPointJwt unauthorizedHandler; + private final UserDetailsServiceImpl userDetailsService; + + private final AuthEntryPointJwt unauthorizedHandler; - @Bean - public AuthTokenFilter authenticationJwtTokenFilter() { - return new AuthTokenFilter(); - } + @Bean + public AuthTokenFilter authenticationJwtTokenFilter() { + return new AuthTokenFilter(); + } - @Override - public void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception { - authenticationManagerBuilder.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder()); - } + @Override + public void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception { + authenticationManagerBuilder.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder()); + } - @Bean - @Override - public AuthenticationManager authenticationManagerBean() throws Exception { - return super.authenticationManagerBean(); - } + @Bean + @Override + public AuthenticationManager authenticationManagerBean() throws Exception { + return super.authenticationManagerBean(); + } - @Bean - public PasswordEncoder passwordEncoder() { - return new BCryptPasswordEncoder(); - } + @Bean + public PasswordEncoder passwordEncoder() { + return new BCryptPasswordEncoder(); + } - @Override - protected void configure(HttpSecurity http) throws Exception { - http.cors().and().csrf().disable() - .exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and() - .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and() - .authorizeRequests().antMatchers("/api/auth/**").permitAll() - .antMatchers("/api/test/**").permitAll() - .anyRequest().authenticated(); + @Override + protected void configure(HttpSecurity http) throws Exception { + http.cors().and().csrf().disable() + .exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and() + .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and() + .authorizeRequests().antMatchers("/api/auth/**").permitAll() + .antMatchers("/api/test/**").permitAll() + .anyRequest().authenticated(); - http.addFilterBefore(authenticationJwtTokenFilter(), UsernamePasswordAuthenticationFilter.class); - } + http.addFilterBefore(authenticationJwtTokenFilter(), UsernamePasswordAuthenticationFilter.class); + } } diff --git a/src/main/java/com/bezkoder/springjwt/security/jwt/AuthEntryPointJwt.java b/src/main/java/com/bezkoder/springjwt/security/jwt/AuthEntryPointJwt.java index 903f6a8..c189b03 100644 --- a/src/main/java/com/bezkoder/springjwt/security/jwt/AuthEntryPointJwt.java +++ b/src/main/java/com/bezkoder/springjwt/security/jwt/AuthEntryPointJwt.java @@ -8,6 +8,7 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import lombok.extern.slf4j.Slf4j; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.MediaType; @@ -17,15 +18,14 @@ import com.fasterxml.jackson.databind.ObjectMapper; +@Slf4j @Component public class AuthEntryPointJwt implements AuthenticationEntryPoint { - private static final Logger logger = LoggerFactory.getLogger(AuthEntryPointJwt.class); - @Override public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException { - logger.error("Unauthorized error: {}", authException.getMessage()); + log.error("Unauthorized error: {}", authException.getMessage()); response.setContentType(MediaType.APPLICATION_JSON_VALUE); response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); diff --git a/src/main/java/com/bezkoder/springjwt/security/jwt/AuthTokenFilter.java b/src/main/java/com/bezkoder/springjwt/security/jwt/AuthTokenFilter.java index 2b3b6d3..a00c528 100644 --- a/src/main/java/com/bezkoder/springjwt/security/jwt/AuthTokenFilter.java +++ b/src/main/java/com/bezkoder/springjwt/security/jwt/AuthTokenFilter.java @@ -1,14 +1,7 @@ package com.bezkoder.springjwt.security.jwt; -import java.io.IOException; - -import javax.servlet.FilterChain; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import com.bezkoder.springjwt.security.services.UserDetailsServiceImpl; +import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.context.SecurityContextHolder; @@ -17,49 +10,52 @@ import org.springframework.util.StringUtils; import org.springframework.web.filter.OncePerRequestFilter; -import com.bezkoder.springjwt.security.services.UserDetailsServiceImpl; +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +@Slf4j public class AuthTokenFilter extends OncePerRequestFilter { - @Autowired - private JwtUtils jwtUtils; - - @Autowired - private UserDetailsServiceImpl userDetailsService; - private static final Logger logger = LoggerFactory.getLogger(AuthTokenFilter.class); - - @Override - protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) - throws ServletException, IOException { - try { - String jwt = parseJwt(request); - if (jwt != null && jwtUtils.validateJwtToken(jwt)) { - String username = jwtUtils.getUserNameFromJwtToken(jwt); - - UserDetails userDetails = userDetailsService.loadUserByUsername(username); - UsernamePasswordAuthenticationToken authentication = - new UsernamePasswordAuthenticationToken( - userDetails, - null, - userDetails.getAuthorities()); - authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); - - SecurityContextHolder.getContext().setAuthentication(authentication); - } - } catch (Exception e) { - logger.error("Cannot set user authentication: {}", e); + @Autowired + private JwtUtils jwtUtils; + + @Autowired + private UserDetailsServiceImpl userDetailsService; + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) + throws ServletException, IOException { + try { + String jwt = parseJwt(request); + if (jwt != null && jwtUtils.validateJwtToken(jwt)) { + String username = jwtUtils.getUserNameFromJwtToken(jwt); + + UserDetails userDetails = userDetailsService.loadUserByUsername(username); + UsernamePasswordAuthenticationToken authentication = + new UsernamePasswordAuthenticationToken( + userDetails, + null, + userDetails.getAuthorities()); + authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); + + SecurityContextHolder.getContext().setAuthentication(authentication); + } + } catch (Exception e) { + logger.error("Cannot set user authentication: {}", e); + } + + filterChain.doFilter(request, response); } - filterChain.doFilter(request, response); - } + private String parseJwt(HttpServletRequest request) { + String headerAuth = request.getHeader("Authorization"); - private String parseJwt(HttpServletRequest request) { - String headerAuth = request.getHeader("Authorization"); - - if (StringUtils.hasText(headerAuth) && headerAuth.startsWith("Bearer ")) { - return headerAuth.substring(7, headerAuth.length()); + if (StringUtils.hasText(headerAuth) && headerAuth.startsWith("Bearer ")) { + return headerAuth.substring(7); + } + return null; } - - return null; - } } diff --git a/src/main/java/com/bezkoder/springjwt/security/jwt/JwtUtils.java b/src/main/java/com/bezkoder/springjwt/security/jwt/JwtUtils.java index 00c8157..e56b2da 100644 --- a/src/main/java/com/bezkoder/springjwt/security/jwt/JwtUtils.java +++ b/src/main/java/com/bezkoder/springjwt/security/jwt/JwtUtils.java @@ -1,58 +1,61 @@ package com.bezkoder.springjwt.security.jwt; -import java.util.Date; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import com.bezkoder.springjwt.security.services.UserDetailsImpl; +import io.jsonwebtoken.ExpiredJwtException; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.MalformedJwtException; +import io.jsonwebtoken.SignatureAlgorithm; +import io.jsonwebtoken.SignatureException; +import io.jsonwebtoken.UnsupportedJwtException; +import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.security.core.Authentication; import org.springframework.stereotype.Component; -import com.bezkoder.springjwt.security.services.UserDetailsImpl; -import io.jsonwebtoken.*; +import java.util.Date; +@Slf4j @Component public class JwtUtils { - private static final Logger logger = LoggerFactory.getLogger(JwtUtils.class); - - @Value("${bezkoder.app.jwtSecret}") - private String jwtSecret; - - @Value("${bezkoder.app.jwtExpirationMs}") - private int jwtExpirationMs; - - public String generateJwtToken(Authentication authentication) { - - UserDetailsImpl userPrincipal = (UserDetailsImpl) authentication.getPrincipal(); - - return Jwts.builder() - .setSubject((userPrincipal.getUsername())) - .setIssuedAt(new Date()) - .setExpiration(new Date((new Date()).getTime() + jwtExpirationMs)) - .signWith(SignatureAlgorithm.HS512, jwtSecret) - .compact(); - } - - public String getUserNameFromJwtToken(String token) { - return Jwts.parser().setSigningKey(jwtSecret).parseClaimsJws(token).getBody().getSubject(); - } - - public boolean validateJwtToken(String authToken) { - try { - Jwts.parser().setSigningKey(jwtSecret).parseClaimsJws(authToken); - return true; - } catch (SignatureException e) { - logger.error("Invalid JWT signature: {}", e.getMessage()); - } catch (MalformedJwtException e) { - logger.error("Invalid JWT token: {}", e.getMessage()); - } catch (ExpiredJwtException e) { - logger.error("JWT token is expired: {}", e.getMessage()); - } catch (UnsupportedJwtException e) { - logger.error("JWT token is unsupported: {}", e.getMessage()); - } catch (IllegalArgumentException e) { - logger.error("JWT claims string is empty: {}", e.getMessage()); + + @Value("${bezkoder.app.jwtSecret}") + private String jwtSecret; + + @Value("${bezkoder.app.jwtExpirationMs}") + private int jwtExpirationMs; + + public String generateJwtToken(Authentication authentication) { + + UserDetailsImpl userPrincipal = (UserDetailsImpl) authentication.getPrincipal(); + + return Jwts.builder() + .setSubject((userPrincipal.getUsername())) + .setIssuedAt(new Date()) + .setExpiration(new Date((new Date()).getTime() + jwtExpirationMs)) + .signWith(SignatureAlgorithm.HS512, jwtSecret) + .compact(); } - return false; - } + public String getUserNameFromJwtToken(String token) { + return Jwts.parser().setSigningKey(jwtSecret).parseClaimsJws(token).getBody().getSubject(); + } + + public boolean validateJwtToken(String authToken) { + try { + Jwts.parser().setSigningKey(jwtSecret).parseClaimsJws(authToken); + return true; + } catch (SignatureException e) { + log.error("Invalid JWT signature: {}", e.getMessage()); + } catch (MalformedJwtException e) { + log.error("Invalid JWT token: {}", e.getMessage()); + } catch (ExpiredJwtException e) { + log.error("JWT token is expired: {}", e.getMessage()); + } catch (UnsupportedJwtException e) { + log.error("JWT token is unsupported: {}", e.getMessage()); + } catch (IllegalArgumentException e) { + log.error("JWT claims string is empty: {}", e.getMessage()); + } + + return false; + } } diff --git a/src/main/java/com/bezkoder/springjwt/security/services/UserDetailsImpl.java b/src/main/java/com/bezkoder/springjwt/security/services/UserDetailsImpl.java index 6452f34..d501c0c 100644 --- a/src/main/java/com/bezkoder/springjwt/security/services/UserDetailsImpl.java +++ b/src/main/java/com/bezkoder/springjwt/security/services/UserDetailsImpl.java @@ -1,103 +1,91 @@ package com.bezkoder.springjwt.security.services; -import java.util.Collection; -import java.util.List; -import java.util.Objects; -import java.util.stream.Collectors; - +import com.bezkoder.springjwt.models.User; +import com.fasterxml.jackson.annotation.JsonIgnore; +import lombok.AllArgsConstructor; +import lombok.Getter; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; -import com.bezkoder.springjwt.models.User; -import com.fasterxml.jackson.annotation.JsonIgnore; +import java.util.Collection; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; +@AllArgsConstructor public class UserDetailsImpl implements UserDetails { - private static final long serialVersionUID = 1L; - - private Long id; - - private String username; - - private String email; - - @JsonIgnore - private String password; - - private Collection authorities; - - public UserDetailsImpl(Long id, String username, String email, String password, - Collection authorities) { - this.id = id; - this.username = username; - this.email = email; - this.password = password; - this.authorities = authorities; - } - - public static UserDetailsImpl build(User user) { - List authorities = user.getRoles().stream() - .map(role -> new SimpleGrantedAuthority(role.getName().name())) - .collect(Collectors.toList()); - - return new UserDetailsImpl( - user.getId(), - user.getUsername(), - user.getEmail(), - user.getPassword(), - authorities); - } - - @Override - public Collection getAuthorities() { - return authorities; - } - - public Long getId() { - return id; - } - - public String getEmail() { - return email; - } - - @Override - public String getPassword() { - return password; - } - - @Override - public String getUsername() { - return username; - } - - @Override - public boolean isAccountNonExpired() { - return true; - } - - @Override - public boolean isAccountNonLocked() { - return true; - } - - @Override - public boolean isCredentialsNonExpired() { - return true; - } - - @Override - public boolean isEnabled() { - return true; - } - - @Override - public boolean equals(Object o) { - if (this == o) - return true; - if (o == null || getClass() != o.getClass()) - return false; - UserDetailsImpl user = (UserDetailsImpl) o; - return Objects.equals(id, user.id); - } + + private static final long serialVersionUID = 1L; + + @Getter + private Long id; + + private String username; + + @Getter + private String email; + + @JsonIgnore + private String password; + + private Collection authorities; + + public static UserDetailsImpl build(User user) { + List authorities = user.getRoles().stream() + .map(role -> new SimpleGrantedAuthority(role.getName().name())) + .collect(Collectors.toList()); + + return new UserDetailsImpl( + user.getId(), + user.getUsername(), + user.getEmail(), + user.getPassword(), + authorities); + } + + @Override + public Collection getAuthorities() { + return authorities; + } + + @Override + public String getPassword() { + return password; + } + + @Override + public String getUsername() { + return username; + } + + @Override + public boolean isAccountNonExpired() { + return true; + } + + @Override + public boolean isAccountNonLocked() { + return true; + } + + @Override + public boolean isCredentialsNonExpired() { + return true; + } + + @Override + public boolean isEnabled() { + return true; + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + UserDetailsImpl user = (UserDetailsImpl) o; + return Objects.equals(id, user.id); + } } diff --git a/src/main/java/com/bezkoder/springjwt/security/services/UserDetailsServiceImpl.java b/src/main/java/com/bezkoder/springjwt/security/services/UserDetailsServiceImpl.java index de65d7e..31e4531 100644 --- a/src/main/java/com/bezkoder/springjwt/security/services/UserDetailsServiceImpl.java +++ b/src/main/java/com/bezkoder/springjwt/security/services/UserDetailsServiceImpl.java @@ -1,27 +1,27 @@ package com.bezkoder.springjwt.security.services; -import org.springframework.beans.factory.annotation.Autowired; +import com.bezkoder.springjwt.models.User; +import com.bezkoder.springjwt.repository.UserRepository; +import lombok.RequiredArgsConstructor; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import com.bezkoder.springjwt.models.User; -import com.bezkoder.springjwt.repository.UserRepository; - @Service +@RequiredArgsConstructor public class UserDetailsServiceImpl implements UserDetailsService { - @Autowired - UserRepository userRepository; - @Override - @Transactional - public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { - User user = userRepository.findByUsername(username) - .orElseThrow(() -> new UsernameNotFoundException("User Not Found with username: " + username)); + private final UserRepository userRepository; + + @Override + @Transactional + public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { + User user = userRepository.findByUsername(username) + .orElseThrow(() -> new UsernameNotFoundException("User Not Found with username: " + username)); - return UserDetailsImpl.build(user); - } + return UserDetailsImpl.build(user); + } } From 474467f5e69eadf625b1999195ae9901711895d1 Mon Sep 17 00:00:00 2001 From: Ramazan Sakin Date: Wed, 27 Jul 2022 06:21:28 +0300 Subject: [PATCH 02/13] chore: username is already unique and not-blank, so its enough to check --- .../com/bezkoder/springjwt/controllers/AuthController.java | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/main/java/com/bezkoder/springjwt/controllers/AuthController.java b/src/main/java/com/bezkoder/springjwt/controllers/AuthController.java index 9eb1c46..be2d5c0 100644 --- a/src/main/java/com/bezkoder/springjwt/controllers/AuthController.java +++ b/src/main/java/com/bezkoder/springjwt/controllers/AuthController.java @@ -76,12 +76,6 @@ public ResponseEntity registerUser(@Valid @RequestBody SignupRequest signUpRe .body(new MessageResponse("Error: Username is already taken!")); } - if (userRepository.existsByEmail(signUpRequest.getEmail())) { - return ResponseEntity - .badRequest() - .body(new MessageResponse("Error: Email is already in use!")); - } - // Create new user's account User user = new User(signUpRequest.getUsername(), signUpRequest.getEmail(), From cc2ecd52d0b554cfa80f10bae312ab8b49ae0483 Mon Sep 17 00:00:00 2001 From: Ramazan Sakin Date: Wed, 27 Jul 2022 06:24:37 +0300 Subject: [PATCH 03/13] chore: clean up --- src/main/resources/application.properties | 2 +- .../springjwt/SpringBootSecurityJwtApplicationTests.java | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index d02fe7a..aca3487 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -5,6 +5,6 @@ spring.datasource.password= 123456 spring.jpa.properties.hibernate.dialect= org.hibernate.dialect.MySQL5InnoDBDialect spring.jpa.hibernate.ddl-auto= update -# App Properties +# JWT Properties bezkoder.app.jwtSecret= bezKoderSecretKey bezkoder.app.jwtExpirationMs= 86400000 \ No newline at end of file diff --git a/src/test/java/com/bezkoder/springjwt/SpringBootSecurityJwtApplicationTests.java b/src/test/java/com/bezkoder/springjwt/SpringBootSecurityJwtApplicationTests.java index 42ffdd0..9282fb5 100644 --- a/src/test/java/com/bezkoder/springjwt/SpringBootSecurityJwtApplicationTests.java +++ b/src/test/java/com/bezkoder/springjwt/SpringBootSecurityJwtApplicationTests.java @@ -4,10 +4,10 @@ import org.springframework.boot.test.context.SpringBootTest; @SpringBootTest -public class SpringBootSecurityJwtApplicationTests { +class SpringBootSecurityJwtApplicationTests { - @Test - public void contextLoads() { - } + @Test + void contextLoads() { + } } From 0950cdde8172fca59e717daa354937103a547d95 Mon Sep 17 00:00:00 2001 From: Ramazan Sakin Date: Wed, 27 Jul 2022 06:26:59 +0300 Subject: [PATCH 04/13] refact: clean up --- README.md | 6 +++--- ...-authentication-spring-security-architecture.png | Bin ...boot-jwt-authentication-spring-security-flow.png | Bin .../spring-boot-refresh-token-jwt-example-flow.png | Bin 4 files changed, 3 insertions(+), 3 deletions(-) rename spring-boot-jwt-authentication-spring-security-architecture.png => misc/spring-boot-jwt-authentication-spring-security-architecture.png (100%) rename spring-boot-jwt-authentication-spring-security-flow.png => misc/spring-boot-jwt-authentication-spring-security-flow.png (100%) rename spring-boot-refresh-token-jwt-example-flow.png => misc/spring-boot-refresh-token-jwt-example-flow.png (100%) diff --git a/README.md b/README.md index 1d95520..22a261d 100644 --- a/README.md +++ b/README.md @@ -3,12 +3,12 @@ ## User Registration, User Login and Authorization process. The diagram shows flow of how we implement User Registration, User Login and Authorization process. -![spring-boot-jwt-authentication-spring-security-flow](spring-boot-jwt-authentication-spring-security-flow.png) +![spring-boot-jwt-authentication-spring-security-flow](misc/spring-boot-jwt-authentication-spring-security-flow.png) ## Spring Boot Server Architecture with Spring Security You can have an overview of our Spring Boot Server with the diagram below: -![spring-boot-jwt-authentication-spring-security-architecture](spring-boot-jwt-authentication-spring-security-architecture.png) +![spring-boot-jwt-authentication-spring-security-architecture](misc/spring-boot-jwt-authentication-spring-security-architecture.png) For more detail, please visit: > [Secure Spring Boot App with Spring Security & JWT Authentication](https://bezkoder.com/spring-boot-jwt-authentication/) @@ -17,7 +17,7 @@ For more detail, please visit: ## Refresh Token -![spring-boot-refresh-token-jwt-example-flow](spring-boot-refresh-token-jwt-example-flow.png) +![spring-boot-refresh-token-jwt-example-flow](misc/spring-boot-refresh-token-jwt-example-flow.png) For instruction: [Spring Boot Refresh Token with JWT example](https://bezkoder.com/spring-boot-refresh-token-jwt/) diff --git a/spring-boot-jwt-authentication-spring-security-architecture.png b/misc/spring-boot-jwt-authentication-spring-security-architecture.png similarity index 100% rename from spring-boot-jwt-authentication-spring-security-architecture.png rename to misc/spring-boot-jwt-authentication-spring-security-architecture.png diff --git a/spring-boot-jwt-authentication-spring-security-flow.png b/misc/spring-boot-jwt-authentication-spring-security-flow.png similarity index 100% rename from spring-boot-jwt-authentication-spring-security-flow.png rename to misc/spring-boot-jwt-authentication-spring-security-flow.png diff --git a/spring-boot-refresh-token-jwt-example-flow.png b/misc/spring-boot-refresh-token-jwt-example-flow.png similarity index 100% rename from spring-boot-refresh-token-jwt-example-flow.png rename to misc/spring-boot-refresh-token-jwt-example-flow.png From 3582edcb8454d343effe1fa6a3096c1bba2f9564 Mon Sep 17 00:00:00 2001 From: Ramazan Sakin Date: Wed, 27 Jul 2022 06:35:16 +0300 Subject: [PATCH 05/13] feat: app dockerized & composed with mysql --- Dockerfile | 5 +++++ docker-compose.yml | 27 +++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 Dockerfile create mode 100644 docker-compose.yml diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..22facb5 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,5 @@ +FROM openjdk:8-alpine +MAINTAINER "Ramazan Sakin" +ADD target/spring-boot-security-jwt-0.0.1-SNAPSHOT.jar spring-boot-security-jwt-0.0.1-SNAPSHOT.jar +EXPOSE 8080 +ENTRYPOINT ["java", "-jar", "spring-boot-security-jwt-0.0.1-SNAPSHOT.jar"] \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..576ce63 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,27 @@ +version: "3.8" +services: + spring-boot-jwt-auth: + build: . + image: spring-boot-jwt-auth-img + ports: + - "8080:8080" + environment: + - spring.profiles.active=docker + depends_on: + - mysqldb + restart: on-failure + + mysqldb: + image: mysql:5.7 + ports: + - "3306:3306" + environment: + - MYSQL_USER=root + - MYSQL_ROOT_PASSWORD=123456 + - MYSQL_DATABASE=testdb + restart: unless-stopped + volumes: + - db:/var/lib/mysql + +volumes: + db: \ No newline at end of file From 523f6ec2507edc1c0728b2ce29b1bf2936702dd3 Mon Sep 17 00:00:00 2001 From: Ramazan Sakin Date: Wed, 27 Jul 2022 06:35:35 +0300 Subject: [PATCH 06/13] feat: docker profile props added --- .../resources/application-docker.properties | 1 + src/main/resources/application.properties | 17 ++++++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) create mode 100644 src/main/resources/application-docker.properties diff --git a/src/main/resources/application-docker.properties b/src/main/resources/application-docker.properties new file mode 100644 index 0000000..0ef9998 --- /dev/null +++ b/src/main/resources/application-docker.properties @@ -0,0 +1 @@ +spring.datasource.url=jdbc:mysql://host.docker.internal:3306/testdb?useSSL=false \ No newline at end of file diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index aca3487..931d2da 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1,10 +1,13 @@ -spring.datasource.url= jdbc:mysql://localhost:3306/testdb?useSSL=false -spring.datasource.username= root -spring.datasource.password= 123456 +server.port=8080 +spring.application.name=spring-boot-jwt-auth -spring.jpa.properties.hibernate.dialect= org.hibernate.dialect.MySQL5InnoDBDialect -spring.jpa.hibernate.ddl-auto= update +spring.datasource.url=jdbc:mysql://localhost:3306/testdb?useSSL=false +spring.datasource.username=root +spring.datasource.password=123456 + +spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect +spring.jpa.hibernate.ddl-auto=update # JWT Properties -bezkoder.app.jwtSecret= bezKoderSecretKey -bezkoder.app.jwtExpirationMs= 86400000 \ No newline at end of file +bezkoder.app.jwtSecret=bezKoderSecretKey +bezkoder.app.jwtExpirationMs=86400000 \ No newline at end of file From 8d5e03c781617d288fccf457fd890e59cf27d570 Mon Sep 17 00:00:00 2001 From: Ramazan Sakin Date: Wed, 27 Jul 2022 07:24:37 +0300 Subject: [PATCH 07/13] feat: docker profile removed --- docker-compose.yml | 17 +++++++++++------ .../resources/application-docker.properties | 1 - src/main/resources/application.properties | 2 +- 3 files changed, 12 insertions(+), 8 deletions(-) delete mode 100644 src/main/resources/application-docker.properties diff --git a/docker-compose.yml b/docker-compose.yml index 576ce63..4b15e53 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,4 +1,4 @@ -version: "3.8" +version: "2.1" services: spring-boot-jwt-auth: build: . @@ -6,9 +6,10 @@ services: ports: - "8080:8080" environment: - - spring.profiles.active=docker + - spring.datasource.url=jdbc:mysql://mysqldb:3306/testdb?useSSL=false depends_on: - - mysqldb + mysqldb: + condition: service_healthy restart: on-failure mysqldb: @@ -16,10 +17,14 @@ services: ports: - "3306:3306" environment: - - MYSQL_USER=root - - MYSQL_ROOT_PASSWORD=123456 - - MYSQL_DATABASE=testdb + MYSQL_USER: "user" + MYSQL_ROOT_PASSWORD: "123456" + MYSQL_DATABASE: "testdb" restart: unless-stopped + healthcheck: + test: [ "CMD", "mysqladmin" ,"ping", "-h", "localhost" ] + timeout: 20s + retries: 10 volumes: - db:/var/lib/mysql diff --git a/src/main/resources/application-docker.properties b/src/main/resources/application-docker.properties deleted file mode 100644 index 0ef9998..0000000 --- a/src/main/resources/application-docker.properties +++ /dev/null @@ -1 +0,0 @@ -spring.datasource.url=jdbc:mysql://host.docker.internal:3306/testdb?useSSL=false \ No newline at end of file diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 931d2da..460958b 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -2,7 +2,7 @@ server.port=8080 spring.application.name=spring-boot-jwt-auth spring.datasource.url=jdbc:mysql://localhost:3306/testdb?useSSL=false -spring.datasource.username=root +spring.datasource.username=user spring.datasource.password=123456 spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect From 519f3faf2b1919ae918955401ff938eb50d6d3a3 Mon Sep 17 00:00:00 2001 From: Ramazan Sakin Date: Wed, 27 Jul 2022 07:56:55 +0300 Subject: [PATCH 08/13] feat: docker-compose & props up --- docker-compose.yml | 13 ++++--------- src/main/resources/application.properties | 2 +- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 4b15e53..d0d66c8 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -17,16 +17,11 @@ services: ports: - "3306:3306" environment: - MYSQL_USER: "user" - MYSQL_ROOT_PASSWORD: "123456" - MYSQL_DATABASE: "testdb" + - MYSQL_ROOT_PASSWORD=123456 + - MYSQL_DATABASE=testdb + - MYSQL_PASSWORD=123456 restart: unless-stopped healthcheck: test: [ "CMD", "mysqladmin" ,"ping", "-h", "localhost" ] timeout: 20s - retries: 10 - volumes: - - db:/var/lib/mysql - -volumes: - db: \ No newline at end of file + retries: 10 \ No newline at end of file diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 460958b..931d2da 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -2,7 +2,7 @@ server.port=8080 spring.application.name=spring-boot-jwt-auth spring.datasource.url=jdbc:mysql://localhost:3306/testdb?useSSL=false -spring.datasource.username=user +spring.datasource.username=root spring.datasource.password=123456 spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect From d710e9474a31f5acf7060335ea5c514bd57cffe6 Mon Sep 17 00:00:00 2001 From: tienbku Date: Fri, 9 Sep 2022 15:27:08 +0700 Subject: [PATCH 09/13] get current changes & resolve conflicts --- README.md | 43 ++++-- pom.xml | 141 ++++++++---------- .../springjwt/security/WebSecurityConfig.java | 120 +++++++++------ 3 files changed, 172 insertions(+), 132 deletions(-) diff --git a/README.md b/README.md index 22a261d..bc298ef 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,27 @@ For more detail, please visit: For instruction: [Spring Boot Refresh Token with JWT example](https://bezkoder.com/spring-boot-refresh-token-jwt/) +## More Practice: +> [Spring Boot File upload example with Multipart File](https://bezkoder.com/spring-boot-file-upload/) + +> [Exception handling: @RestControllerAdvice example in Spring Boot](https://bezkoder.com/spring-boot-restcontrolleradvice/) + +> [Spring Boot Repository Unit Test with @DataJpaTest](https://bezkoder.com/spring-boot-unit-test-jpa-repo-datajpatest/) + +> [Spring Boot Pagination & Sorting example](https://www.bezkoder.com/spring-boot-pagination-sorting-example/) + +Associations: +> [Spring Boot One To Many example with Spring JPA, Hibernate](https://www.bezkoder.com/jpa-one-to-many/) + +> [Spring Boot Many To Many example with Spring JPA, Hibernate](https://www.bezkoder.com/jpa-many-to-many/) + +> [JPA One To One example with Spring Boot](https://www.bezkoder.com/jpa-one-to-one/) + +Deployment: +> [Deploy Spring Boot App on AWS – Elastic Beanstalk](https://www.bezkoder.com/deploy-spring-boot-aws-eb/) + +> [Docker Compose Spring Boot and MySQL example](https://www.bezkoder.com/docker-compose-spring-boot-mysql/) + ## Fullstack Authentication > [Spring Boot + Vue.js JWT Authentication](https://bezkoder.com/spring-boot-vue-js-authentication-jwt-spring-security/) @@ -33,6 +54,10 @@ For instruction: [Spring Boot Refresh Token with JWT example](https://bezkoder.c > [Spring Boot + Angular 12 JWT Authentication](https://www.bezkoder.com/angular-12-spring-boot-jwt-auth/) +> [Spring Boot + Angular 13 JWT Authentication](https://www.bezkoder.com/angular-13-spring-boot-jwt-auth/) + +> [Spring Boot + Angular 14 JWT Authentication](https://www.bezkoder.com/angular-14-spring-boot-jwt-auth/) + > [Spring Boot + React JWT Authentication](https://bezkoder.com/spring-boot-react-jwt-auth/) ## Fullstack CRUD App @@ -69,6 +94,12 @@ For instruction: [Spring Boot Refresh Token with JWT example](https://bezkoder.c > [Angular 13 + Spring Boot + PostgreSQL example](https://www.bezkoder.com/spring-boot-angular-13-postgresql/) +> [Angular 14 + Spring Boot + H2 Embedded Database example](https://www.bezkoder.com/spring-boot-angular-14-crud/) + +> [Angular 14 + Spring Boot + MySQL example](https://www.bezkoder.com/spring-boot-angular-14-mysql/) + +> [Angular 14 + Spring Boot + PostgreSQL example](https://www.bezkoder.com/spring-boot-angular-14-postgresql/) + > [React + Spring Boot + MySQL example](https://bezkoder.com/react-spring-boot-crud/) > [React + Spring Boot + PostgreSQL example](https://bezkoder.com/spring-boot-react-postgresql/) @@ -82,18 +113,6 @@ Run both Back-end & Front-end in one place: > [Integrate Vue.js with Spring Boot Rest API](https://bezkoder.com/integrate-vue-spring-boot/) -More Practice: -> [Spring Boot File upload example with Multipart File](https://bezkoder.com/spring-boot-file-upload/) - -> [Exception handling: @RestControllerAdvice example in Spring Boot](https://bezkoder.com/spring-boot-restcontrolleradvice/) - -> [Spring Boot Repository Unit Test with @DataJpaTest](https://bezkoder.com/spring-boot-unit-test-jpa-repo-datajpatest/) - -Deployment: -> [Deploy Spring Boot App on AWS – Elastic Beanstalk](https://www.bezkoder.com/deploy-spring-boot-aws-eb/) - -> [Docker Compose Spring Boot and MySQL example](https://www.bezkoder.com/docker-compose-spring-boot-mysql/) - ## Dependency – If you want to use PostgreSQL: ```xml diff --git a/pom.xml b/pom.xml index 18639fc..b39061d 100644 --- a/pom.xml +++ b/pom.xml @@ -1,90 +1,77 @@ - 4.0.0 - - org.springframework.boot - spring-boot-starter-parent - 2.6.1 - - - com.bezkoder - spring-boot-security-jwt - 0.0.1-SNAPSHOT - spring-boot-security-jwt - Demo project for Spring Boot Security - JWT + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.7.3 + + + com.bezkoder + spring-boot-security-jwt + 0.0.1-SNAPSHOT + spring-boot-security-jwt + Demo project for Spring Boot Security - JWT - - 1.8 - + + 1.8 + - - - org.springframework.boot - spring-boot-starter-data-jpa - + + + org.springframework.boot + spring-boot-starter-data-jpa + - - org.springframework.boot - spring-boot-starter-security - + + org.springframework.boot + spring-boot-starter-security + + + + org.springframework.boot + spring-boot-starter-validation + - - org.springframework.boot - spring-boot-starter-validation - + + org.springframework.boot + spring-boot-starter-web + - - org.springframework.boot - spring-boot-starter-web - + + mysql + mysql-connector-java + runtime + - - mysql - mysql-connector-java - runtime - + + io.jsonwebtoken + jjwt + 0.9.1 + - - io.jsonwebtoken - jjwt - 0.9.1 - - - org.projectlombok - lombok - 1.18.24 - + + org.springframework.boot + spring-boot-starter-test + test + - - org.springframework.boot - spring-boot-starter-test - test - + + org.springframework.security + spring-security-test + test + + - - org.springframework.security - spring-security-test - test - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - org.projectlombok - lombok - - - - - - + + + + org.springframework.boot + spring-boot-maven-plugin + + + diff --git a/src/main/java/com/bezkoder/springjwt/security/WebSecurityConfig.java b/src/main/java/com/bezkoder/springjwt/security/WebSecurityConfig.java index b07555d..3114f6b 100644 --- a/src/main/java/com/bezkoder/springjwt/security/WebSecurityConfig.java +++ b/src/main/java/com/bezkoder/springjwt/security/WebSecurityConfig.java @@ -1,65 +1,99 @@ package com.bezkoder.springjwt.security; -import com.bezkoder.springjwt.security.jwt.AuthEntryPointJwt; -import com.bezkoder.springjwt.security.jwt.AuthTokenFilter; -import com.bezkoder.springjwt.security.services.UserDetailsServiceImpl; -import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.AuthenticationManager; -import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.authentication.dao.DaoAuthenticationProvider; +//import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration; 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.configuration.EnableWebSecurity; -import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +//import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +//import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.config.http.SessionCreationPolicy; 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; -@RequiredArgsConstructor +import com.bezkoder.springjwt.security.jwt.AuthEntryPointJwt; +import com.bezkoder.springjwt.security.jwt.AuthTokenFilter; +import com.bezkoder.springjwt.security.services.UserDetailsServiceImpl; + @Configuration -@EnableWebSecurity @EnableGlobalMethodSecurity( - // securedEnabled = true, - // jsr250Enabled = true, - prePostEnabled = true) -public class WebSecurityConfig extends WebSecurityConfigurerAdapter { - - private final UserDetailsServiceImpl userDetailsService; + // securedEnabled = true, + // jsr250Enabled = true, + prePostEnabled = true) +public class WebSecurityConfig { // extends WebSecurityConfigurerAdapter { + @Autowired + UserDetailsServiceImpl userDetailsService; - private final AuthEntryPointJwt unauthorizedHandler; + @Autowired + private AuthEntryPointJwt unauthorizedHandler; - @Bean - public AuthTokenFilter authenticationJwtTokenFilter() { - return new AuthTokenFilter(); - } + @Bean + public AuthTokenFilter authenticationJwtTokenFilter() { + return new AuthTokenFilter(); + } - @Override - public void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception { - authenticationManagerBuilder.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder()); - } +// @Override +// public void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception { +// authenticationManagerBuilder.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder()); +// } + + @Bean + public DaoAuthenticationProvider authenticationProvider() { + DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider(); + + authProvider.setUserDetailsService(userDetailsService); + authProvider.setPasswordEncoder(passwordEncoder()); + + return authProvider; + } - @Bean - @Override - public AuthenticationManager authenticationManagerBean() throws Exception { - return super.authenticationManagerBean(); - } +// @Bean +// @Override +// public AuthenticationManager authenticationManagerBean() throws Exception { +// return super.authenticationManagerBean(); +// } + + @Bean + public AuthenticationManager authenticationManager(AuthenticationConfiguration authConfig) throws Exception { + return authConfig.getAuthenticationManager(); + } - @Bean - public PasswordEncoder passwordEncoder() { - return new BCryptPasswordEncoder(); - } + @Bean + public PasswordEncoder passwordEncoder() { + return new BCryptPasswordEncoder(); + } - @Override - protected void configure(HttpSecurity http) throws Exception { - http.cors().and().csrf().disable() - .exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and() - .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and() - .authorizeRequests().antMatchers("/api/auth/**").permitAll() - .antMatchers("/api/test/**").permitAll() - .anyRequest().authenticated(); +// @Override +// protected void configure(HttpSecurity http) throws Exception { +// http.cors().and().csrf().disable() +// .exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and() +// .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and() +// .authorizeRequests().antMatchers("/api/auth/**").permitAll() +// .antMatchers("/api/test/**").permitAll() +// .anyRequest().authenticated(); +// +// http.addFilterBefore(authenticationJwtTokenFilter(), UsernamePasswordAuthenticationFilter.class); +// } + + @Bean + public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { + http.cors().and().csrf().disable() + .exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and() + .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and() + .authorizeRequests().antMatchers("/api/auth/**").permitAll() + .antMatchers("/api/test/**").permitAll() + .anyRequest().authenticated(); + + http.authenticationProvider(authenticationProvider()); - http.addFilterBefore(authenticationJwtTokenFilter(), UsernamePasswordAuthenticationFilter.class); - } + http.addFilterBefore(authenticationJwtTokenFilter(), UsernamePasswordAuthenticationFilter.class); + + return http.build(); + } } From 969039dcd85be34c01652737be362df7cc1c6395 Mon Sep 17 00:00:00 2001 From: Ramazan Sakin Date: Sat, 8 Apr 2023 10:32:41 +0300 Subject: [PATCH 10/13] userSSL is removed not to get connection problem but it needs to be configured for production --- 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 931d2da..403bc59 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1,7 +1,7 @@ server.port=8080 spring.application.name=spring-boot-jwt-auth -spring.datasource.url=jdbc:mysql://localhost:3306/testdb?useSSL=false +spring.datasource.url=jdbc:mysql://localhost:3306/testdb spring.datasource.username=root spring.datasource.password=123456 From 5f6d3c495814e4894bb8628ed0fd1a669fb48101 Mon Sep 17 00:00:00 2001 From: Ramazan Sakin Date: Sat, 8 Apr 2023 10:33:15 +0300 Subject: [PATCH 11/13] SignupRequest required fields defined --- .../com/bezkoder/springjwt/payload/request/SignupRequest.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/com/bezkoder/springjwt/payload/request/SignupRequest.java b/src/main/java/com/bezkoder/springjwt/payload/request/SignupRequest.java index 68d0aa3..1353d6c 100644 --- a/src/main/java/com/bezkoder/springjwt/payload/request/SignupRequest.java +++ b/src/main/java/com/bezkoder/springjwt/payload/request/SignupRequest.java @@ -3,21 +3,25 @@ import lombok.Value; import javax.validation.constraints.Email; +import javax.validation.constraints.NotBlank; import javax.validation.constraints.Size; import java.util.Set; @Value public class SignupRequest { + @NotBlank(message = "username is required") @Size(min = 3, max = 20) String username; + @NotBlank(message = "email is required") @Size(max = 50) @Email String email; Set roles; + @NotBlank(message = "password is required") @Size(min = 6, max = 40) String password; From 5f2ae8c4a4b4ae2fba95a9b8f5561912c1402ebe Mon Sep 17 00:00:00 2001 From: Ramazan Sakin Date: Sat, 8 Apr 2023 10:33:40 +0300 Subject: [PATCH 12/13] pre-defined roles initialized not to get "Role not found" error --- .../SpringBootSecurityJwtApplication.java | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/main/java/com/bezkoder/springjwt/SpringBootSecurityJwtApplication.java b/src/main/java/com/bezkoder/springjwt/SpringBootSecurityJwtApplication.java index 4c6d3b1..3498a22 100644 --- a/src/main/java/com/bezkoder/springjwt/SpringBootSecurityJwtApplication.java +++ b/src/main/java/com/bezkoder/springjwt/SpringBootSecurityJwtApplication.java @@ -1,13 +1,35 @@ package com.bezkoder.springjwt; +import com.bezkoder.springjwt.models.ERole; +import com.bezkoder.springjwt.models.Role; +import com.bezkoder.springjwt.repository.RoleRepository; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import javax.annotation.PostConstruct; +import java.util.Optional; + @SpringBootApplication public class SpringBootSecurityJwtApplication { + @Autowired + private RoleRepository roleRepository; + public static void main(String[] args) { SpringApplication.run(SpringBootSecurityJwtApplication.class, args); } + @PostConstruct + public void init() { + // Create roles if they don't exist + for (ERole role : ERole.values()) { + Optional optionalRole = roleRepository.findByName(role); + if (!optionalRole.isPresent()) { + Role newRole = new Role(); + newRole.setName(role); + roleRepository.save(newRole); + } + } + } } \ No newline at end of file From a0c2e700007056d59d23022491259e38e3014088 Mon Sep 17 00:00:00 2001 From: Ramazan Sakin Date: Sat, 8 Apr 2023 10:38:07 +0300 Subject: [PATCH 13/13] docker-compose up & lombok dep added --- docker-compose.yml | 10 +++++----- pom.xml | 6 ++++++ 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index d0d66c8..f241a3c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -2,18 +2,18 @@ version: "2.1" services: spring-boot-jwt-auth: build: . - image: spring-boot-jwt-auth-img + image: spring-boot-jwt-auth ports: - "8080:8080" environment: - - spring.datasource.url=jdbc:mysql://mysqldb:3306/testdb?useSSL=false + - spring.datasource.url=jdbc:mysql://mysqldb:3306/testdb depends_on: mysqldb: condition: service_healthy restart: on-failure mysqldb: - image: mysql:5.7 + image: mysql:8.0.32 ports: - "3306:3306" environment: @@ -23,5 +23,5 @@ services: restart: unless-stopped healthcheck: test: [ "CMD", "mysqladmin" ,"ping", "-h", "localhost" ] - timeout: 20s - retries: 10 \ No newline at end of file + timeout: 10s + retries: 5 \ No newline at end of file diff --git a/pom.xml b/pom.xml index b39061d..c1078c5 100644 --- a/pom.xml +++ b/pom.xml @@ -52,6 +52,12 @@ 0.9.1 + + org.projectlombok + lombok + 1.18.26 + + org.springframework.boot spring-boot-starter-test