From 79af1260cf5a0e26facdf32ef4df4e82ea191a9b Mon Sep 17 00:00:00 2001 From: "Dr. Alwin Simon" <003alwin@gmail.com> Date: Mon, 11 Dec 2023 08:58:04 +0530 Subject: [PATCH 1/8] Updated Token Expiration time to 24 Hours. --- .../UserManagementJavaSpringBoot/Service/JwtService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/alwinsimon/UserManagementJavaSpringBoot/Service/JwtService.java b/src/main/java/com/alwinsimon/UserManagementJavaSpringBoot/Service/JwtService.java index 0869b7d..f1ccf07 100644 --- a/src/main/java/com/alwinsimon/UserManagementJavaSpringBoot/Service/JwtService.java +++ b/src/main/java/com/alwinsimon/UserManagementJavaSpringBoot/Service/JwtService.java @@ -65,7 +65,7 @@ public String generateJwtToken(Map additionalClaims, UserDetails .setClaims(additionalClaims) .setSubject(userDetails.getUsername()) .setIssuedAt(new Date(System.currentTimeMillis())) - .setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 24)) + .setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 24)) // 24 hours .signWith(getJwtSigningKey(), SignatureAlgorithm.HS256) .compact(); From 1ceb115134ae175e65a59502d16a9b529e22ebec Mon Sep 17 00:00:00 2001 From: "Dr. Alwin Simon" <003alwin@gmail.com> Date: Mon, 11 Dec 2023 10:55:32 +0530 Subject: [PATCH 2/8] Added exception handling. --- .../Controller/UserController.java | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/alwinsimon/UserManagementJavaSpringBoot/Controller/UserController.java b/src/main/java/com/alwinsimon/UserManagementJavaSpringBoot/Controller/UserController.java index 1afbf03..437736b 100644 --- a/src/main/java/com/alwinsimon/UserManagementJavaSpringBoot/Controller/UserController.java +++ b/src/main/java/com/alwinsimon/UserManagementJavaSpringBoot/Controller/UserController.java @@ -3,6 +3,8 @@ import com.alwinsimon.UserManagementJavaSpringBoot.Model.User; import com.alwinsimon.UserManagementJavaSpringBoot.Service.UserService; import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; @@ -17,10 +19,13 @@ public class UserController { private final UserService userService; @GetMapping("/current-user") - public User getCurrentUser() { - - // API Endpoint to get the LoggedIn User Details using Token received in the Request Header. - return userService.currentUserDetails(); - + public ResponseEntity getCurrentUser() throws Exception { + try { + // API Endpoint to get the LoggedIn User Details using Token received in the Request Header. + User user = userService.currentUserDetails(); + return ResponseEntity.ok(user); + } catch (Exception e) { + throw new UsernameNotFoundException("User not found."); + } } } From e2d7547f0a70cd7740ad4f17cf99e14e4ff88d04 Mon Sep 17 00:00:00 2001 From: "Dr. Alwin Simon" <003alwin@gmail.com> Date: Mon, 11 Dec 2023 10:59:48 +0530 Subject: [PATCH 3/8] Standardized response. --- .../Controller/GeneralController.java | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/alwinsimon/UserManagementJavaSpringBoot/Controller/GeneralController.java b/src/main/java/com/alwinsimon/UserManagementJavaSpringBoot/Controller/GeneralController.java index bed525f..b7f8c63 100644 --- a/src/main/java/com/alwinsimon/UserManagementJavaSpringBoot/Controller/GeneralController.java +++ b/src/main/java/com/alwinsimon/UserManagementJavaSpringBoot/Controller/GeneralController.java @@ -1,5 +1,6 @@ package com.alwinsimon.UserManagementJavaSpringBoot.Controller; +import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; @@ -17,18 +18,19 @@ public class GeneralController { @GetMapping("/") - public Map getServerStatus() { - - // Get the current date and time in UTC + public ResponseEntity> getServerStatus() { ZonedDateTime currentDateTimeUtc = ZonedDateTime.now(ZoneOffset.UTC); DateTimeFormatter formatter = DateTimeFormatter.ofPattern("EEEE, MMMM dd, yyyy, hh:mm:ss a"); String formattedDateTime = currentDateTimeUtc.format(formatter); - // Create a Map for the response - Map response = new HashMap<>(); - response.put("status", "SERVER and Systems are Up & Running."); - response.put("dateTime", formattedDateTime); + Map data = new HashMap<>(); + data.put("status", "SERVER and Systems are Up & Running."); + data.put("dateTime", formattedDateTime); + + Map response = new HashMap<>(); + response.put("data", data); - return response; + return ResponseEntity.ok(response); } + } From 03cd341139cf51645ee76a4b7ecf4e9a764b19ce Mon Sep 17 00:00:00 2001 From: "Dr. Alwin Simon" <003alwin@gmail.com> Date: Mon, 11 Dec 2023 11:03:14 +0530 Subject: [PATCH 4/8] Overrided a JPA method to delete user by ID. --- .../Repository/UserRepository.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/com/alwinsimon/UserManagementJavaSpringBoot/Repository/UserRepository.java b/src/main/java/com/alwinsimon/UserManagementJavaSpringBoot/Repository/UserRepository.java index 96f3e4b..fc24d37 100644 --- a/src/main/java/com/alwinsimon/UserManagementJavaSpringBoot/Repository/UserRepository.java +++ b/src/main/java/com/alwinsimon/UserManagementJavaSpringBoot/Repository/UserRepository.java @@ -8,4 +8,7 @@ public interface UserRepository extends JpaRepository { Optional findByEmail(String email); + @Override + void deleteById(Long id); + } From 791da9bc9e6ee1f13e39cab29744ae0cb20bba77 Mon Sep 17 00:00:00 2001 From: "Dr. Alwin Simon" <003alwin@gmail.com> Date: Mon, 11 Dec 2023 11:07:42 +0530 Subject: [PATCH 5/8] Added Admin controller and Service. --- .../Controller/AdminController.java | 39 ++++++++++++++++++ .../Service/AdminService.java | 40 +++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 src/main/java/com/alwinsimon/UserManagementJavaSpringBoot/Controller/AdminController.java create mode 100644 src/main/java/com/alwinsimon/UserManagementJavaSpringBoot/Service/AdminService.java diff --git a/src/main/java/com/alwinsimon/UserManagementJavaSpringBoot/Controller/AdminController.java b/src/main/java/com/alwinsimon/UserManagementJavaSpringBoot/Controller/AdminController.java new file mode 100644 index 0000000..5bfbb1b --- /dev/null +++ b/src/main/java/com/alwinsimon/UserManagementJavaSpringBoot/Controller/AdminController.java @@ -0,0 +1,39 @@ +package com.alwinsimon.UserManagementJavaSpringBoot.Controller; + +import com.alwinsimon.UserManagementJavaSpringBoot.Model.User; +import com.alwinsimon.UserManagementJavaSpringBoot.Service.AdminService; +import com.alwinsimon.UserManagementJavaSpringBoot.Service.UserService; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@RestController +@RequestMapping("/api/v1/admin") +@RequiredArgsConstructor +@CrossOrigin("*") +public class AdminController { + + private final AdminService adminService; + @GetMapping("/get-users") + public ResponseEntity> getAllUsers() { + + // API Endpoint to get the LoggedIn User Details using Token received in the Request Header. + List users = adminService.getAllUsers(); + return ResponseEntity.ok(users); + + } + + @DeleteMapping("/delete-user/{email}") + public ResponseEntity deleteUser(@PathVariable("email")String email){ + try { + adminService.deleteUserByEmail(email); + return ResponseEntity.ok("User deleted."); + }catch (Exception e){ + return ResponseEntity.status(HttpStatus.NOT_FOUND).body("User deletion Failed."); + } + } +} diff --git a/src/main/java/com/alwinsimon/UserManagementJavaSpringBoot/Service/AdminService.java b/src/main/java/com/alwinsimon/UserManagementJavaSpringBoot/Service/AdminService.java new file mode 100644 index 0000000..b7372cd --- /dev/null +++ b/src/main/java/com/alwinsimon/UserManagementJavaSpringBoot/Service/AdminService.java @@ -0,0 +1,40 @@ +package com.alwinsimon.UserManagementJavaSpringBoot.Service; + +import com.alwinsimon.UserManagementJavaSpringBoot.Model.User; +import com.alwinsimon.UserManagementJavaSpringBoot.Repository.UserRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.dao.EmptyResultDataAccessException; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +@RequiredArgsConstructor +public class AdminService { + + private final UserRepository userRepository; + + + public List getAllUsers() { + return userRepository.findAll(); + } + + public void deleteUserByEmail(String email) throws Exception { + + User userToDelete = userRepository.findByEmail(email) + .orElseThrow(() -> new UsernameNotFoundException("User not found.")); + + try { + + userRepository.deleteById(userToDelete.getId()); + + } catch (EmptyResultDataAccessException e) { + + throw new UsernameNotFoundException("User Deletion FAILED.", e); + + } + + } + +} From 3ec937f9cb012f6b9627c22f64a665faa049db5f Mon Sep 17 00:00:00 2001 From: "Dr. Alwin Simon" <003alwin@gmail.com> Date: Mon, 11 Dec 2023 12:15:05 +0530 Subject: [PATCH 6/8] Moved all Service Implementation to a single directory. --- .../AdminServiceImplementation.java | 44 +++++++ .../AuthenticationServiceImplementation.java | 76 ++++++++++++ .../JwtServiceImplementation.java | 115 ++++++++++++++++++ .../UserServiceImplementation.java | 22 ++++ 4 files changed, 257 insertions(+) create mode 100644 src/main/java/com/alwinsimon/UserManagementJavaSpringBoot/Service/Implementation/AdminServiceImplementation.java create mode 100644 src/main/java/com/alwinsimon/UserManagementJavaSpringBoot/Service/Implementation/AuthenticationServiceImplementation.java create mode 100644 src/main/java/com/alwinsimon/UserManagementJavaSpringBoot/Service/Implementation/JwtServiceImplementation.java create mode 100644 src/main/java/com/alwinsimon/UserManagementJavaSpringBoot/Service/Implementation/UserServiceImplementation.java diff --git a/src/main/java/com/alwinsimon/UserManagementJavaSpringBoot/Service/Implementation/AdminServiceImplementation.java b/src/main/java/com/alwinsimon/UserManagementJavaSpringBoot/Service/Implementation/AdminServiceImplementation.java new file mode 100644 index 0000000..5c6731e --- /dev/null +++ b/src/main/java/com/alwinsimon/UserManagementJavaSpringBoot/Service/Implementation/AdminServiceImplementation.java @@ -0,0 +1,44 @@ +package com.alwinsimon.UserManagementJavaSpringBoot.Service.Implementation; + +import com.alwinsimon.UserManagementJavaSpringBoot.Model.User; +import com.alwinsimon.UserManagementJavaSpringBoot.Repository.UserRepository; +import com.alwinsimon.UserManagementJavaSpringBoot.Service.AdminService; +import lombok.RequiredArgsConstructor; +import org.springframework.dao.EmptyResultDataAccessException; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +@RequiredArgsConstructor +public class AdminServiceImplementation implements AdminService { + + private final UserRepository userRepository; + + + public List getAllUsers() { + + // Fetch and Returns All users from DB + return userRepository.findAll(); + + } + + public void deleteUserByEmail(String email) { + + User userToDelete = userRepository.findByEmail(email) + .orElseThrow(() -> new UsernameNotFoundException("User not found.")); + + try { + + userRepository.deleteById(userToDelete.getId()); + + } catch (EmptyResultDataAccessException e) { + + throw new UsernameNotFoundException("User Deletion FAILED.", e); + + } + + } + +} diff --git a/src/main/java/com/alwinsimon/UserManagementJavaSpringBoot/Service/Implementation/AuthenticationServiceImplementation.java b/src/main/java/com/alwinsimon/UserManagementJavaSpringBoot/Service/Implementation/AuthenticationServiceImplementation.java new file mode 100644 index 0000000..fed64ab --- /dev/null +++ b/src/main/java/com/alwinsimon/UserManagementJavaSpringBoot/Service/Implementation/AuthenticationServiceImplementation.java @@ -0,0 +1,76 @@ +package com.alwinsimon.UserManagementJavaSpringBoot.Service.Implementation; + +import com.alwinsimon.UserManagementJavaSpringBoot.Config.Auth.AuthenticationRequest; +import com.alwinsimon.UserManagementJavaSpringBoot.Config.Auth.AuthenticationResponse; +import com.alwinsimon.UserManagementJavaSpringBoot.Config.Auth.RegisterRequest; +import com.alwinsimon.UserManagementJavaSpringBoot.Model.Role; +import com.alwinsimon.UserManagementJavaSpringBoot.Model.User; +import com.alwinsimon.UserManagementJavaSpringBoot.Repository.UserRepository; +import com.alwinsimon.UserManagementJavaSpringBoot.Service.AuthenticationService; +import lombok.RequiredArgsConstructor; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class AuthenticationServiceImplementation implements AuthenticationService { + + private final UserRepository userRepository; + private final PasswordEncoder passwordEncoder; + private final JwtServiceImplementation jwtService; + private final AuthenticationManager authenticationManager; + + public AuthenticationResponse register(RegisterRequest request) { + + // Build a user using builder in user model. + var user = User.builder() + .name(request.getName()) + .gender(request.getGender()) + .email(request.getEmail()) + .password(passwordEncoder.encode(request.getPassword())) + .role(Role.USER) + .build(); + + // Save User to DB using UserRepository + userRepository.save(user); + + // Generate a JWT Token to return along with Response. + var jwtToken = jwtService.generateJwtToken(user); + + return AuthenticationResponse.builder() + .token(jwtToken) + .build(); + + } + + public AuthenticationResponse authenticate(AuthenticationRequest request) { + + // Try Authenticating user with Authentication Manager + authenticationManager.authenticate( + new UsernamePasswordAuthenticationToken( + request.getEmail(), + request.getPassword() + ) + ); + + /** + * If the authentication manager authenticated user without throwing any exception + * Find user and generate auth token + * Send auth token back to user. + */ + + var user = userRepository.findByEmail(request.getEmail()) + .orElseThrow(() -> new UsernameNotFoundException("User not found.")); + + // Generate a JWT Token to return along with Response. + var jwtToken = jwtService.generateJwtToken(user); + + return AuthenticationResponse.builder() + .token(jwtToken) + .build(); + + } +} diff --git a/src/main/java/com/alwinsimon/UserManagementJavaSpringBoot/Service/Implementation/JwtServiceImplementation.java b/src/main/java/com/alwinsimon/UserManagementJavaSpringBoot/Service/Implementation/JwtServiceImplementation.java new file mode 100644 index 0000000..70f2205 --- /dev/null +++ b/src/main/java/com/alwinsimon/UserManagementJavaSpringBoot/Service/Implementation/JwtServiceImplementation.java @@ -0,0 +1,115 @@ +package com.alwinsimon.UserManagementJavaSpringBoot.Service.Implementation; + +import com.alwinsimon.UserManagementJavaSpringBoot.Service.JwtService; +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.SignatureAlgorithm; +import io.jsonwebtoken.io.Decoders; +import io.jsonwebtoken.security.Keys; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.stereotype.Service; + +import java.security.Key; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.function.Function; + +@Service +public class JwtServiceImplementation implements JwtService { + + // Set Signing Key for Signing JWT Tokens + private static final String JWT_SECRET_KEY = "2F66554775577754346D56726D7933315266773239773D3D"; + + private Key getJwtSigningKey() { + // Function to provide JWT_SECRET_KEY + + byte[] keyBytes = Decoders.BASE64.decode(JWT_SECRET_KEY); + return Keys.hmacShaKeyFor(keyBytes); + + } + + public String extractUsername(String jwtToken) { + // Decrypt jwt token and return Username + + return extractClaimFromJwtToken(jwtToken, Claims::getSubject); + + } + + private Claims extractAllClaimsFromJwtToken(String jwtToken) { + // Function to Extract ALL claims from JWT Token + + return Jwts + .parserBuilder() + .setSigningKey(getJwtSigningKey()) + .build() + .parseClaimsJws(jwtToken) + .getBody(); + + } + + public T extractClaimFromJwtToken(String jwtToken, Function claimsResolver) { + // Function to Extract single claim from JWT Token + + final Claims claims = extractAllClaimsFromJwtToken(jwtToken); + return claimsResolver.apply(claims); + + } + + public String generateJwtToken(Map additionalClaims, UserDetails userDetails) { + /** + * Function to generate JWT Token With Additional Claims + */ + + return Jwts + .builder() + .setClaims(additionalClaims) + .setSubject(userDetails.getUsername()) + .setIssuedAt(new Date(System.currentTimeMillis())) + .setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 24)) // 24 hours + .signWith(getJwtSigningKey(), SignatureAlgorithm.HS256) + .compact(); + + } + + public String generateJwtToken(UserDetails userDetails) { + /** + * Function to generate JWT Token without any extra claims + * Internally uses generateJwtToken method which takes in additional claims + * In place of additional claims, passes an empty HashMap + */ + + return generateJwtToken(new HashMap<>(), userDetails); + + } + + public boolean isTokenValid(String jwtToken, UserDetails userDetails) { + /** + * Function to check the provided token is valid for the user and is not expired. + */ + + final String userName = extractUsername(jwtToken); + return (userName.equals(userDetails.getUsername()) && !isTokenExpired(jwtToken)); + + } + + private boolean isTokenExpired(String jwtToken) { + /** + * Function to check the provided token is valid for the user and is not expired. + */ + + return extractJwtTokenExpiration(jwtToken).before(new Date()); + + } + + private Date extractJwtTokenExpiration(String jwtToken) { + /** + * Function to return the expiration date of a provided Jwt Token + * Internally uses extractClaimFromJwtToken method which takes in token and a single required claim + * In place of single required claims, passes a claim to get expiration + */ + + return extractClaimFromJwtToken(jwtToken, Claims::getExpiration); + + } +} diff --git a/src/main/java/com/alwinsimon/UserManagementJavaSpringBoot/Service/Implementation/UserServiceImplementation.java b/src/main/java/com/alwinsimon/UserManagementJavaSpringBoot/Service/Implementation/UserServiceImplementation.java new file mode 100644 index 0000000..6f03d85 --- /dev/null +++ b/src/main/java/com/alwinsimon/UserManagementJavaSpringBoot/Service/Implementation/UserServiceImplementation.java @@ -0,0 +1,22 @@ +package com.alwinsimon.UserManagementJavaSpringBoot.Service.Implementation; + +import com.alwinsimon.UserManagementJavaSpringBoot.Model.User; +import com.alwinsimon.UserManagementJavaSpringBoot.Repository.UserRepository; +import com.alwinsimon.UserManagementJavaSpringBoot.Service.UserService; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.security.Principal; + +@Service +@RequiredArgsConstructor +public class UserServiceImplementation implements UserService { + + private final UserRepository userRepository; + private final Principal principal; + + public User currentUserDetails() { + String email = principal.getName(); + return userRepository.findByEmail(email).orElse(null); + } +} From 29db4b6f608e2696b48e7b2a1a38856413eb76b0 Mon Sep 17 00:00:00 2001 From: "Dr. Alwin Simon" <003alwin@gmail.com> Date: Mon, 11 Dec 2023 12:15:47 +0530 Subject: [PATCH 7/8] Exposed Interfaces for all the Services. --- .../Service/AdminService.java | 34 +----- .../Service/AuthenticationService.java | 68 +----------- .../Service/JwtService.java | 105 +----------------- .../Service/UserService.java | 15 +-- 4 files changed, 14 insertions(+), 208 deletions(-) diff --git a/src/main/java/com/alwinsimon/UserManagementJavaSpringBoot/Service/AdminService.java b/src/main/java/com/alwinsimon/UserManagementJavaSpringBoot/Service/AdminService.java index b7372cd..7308e99 100644 --- a/src/main/java/com/alwinsimon/UserManagementJavaSpringBoot/Service/AdminService.java +++ b/src/main/java/com/alwinsimon/UserManagementJavaSpringBoot/Service/AdminService.java @@ -1,40 +1,12 @@ package com.alwinsimon.UserManagementJavaSpringBoot.Service; import com.alwinsimon.UserManagementJavaSpringBoot.Model.User; -import com.alwinsimon.UserManagementJavaSpringBoot.Repository.UserRepository; -import lombok.RequiredArgsConstructor; -import org.springframework.dao.EmptyResultDataAccessException; -import org.springframework.security.core.userdetails.UsernameNotFoundException; -import org.springframework.stereotype.Service; - import java.util.List; -@Service -@RequiredArgsConstructor -public class AdminService { - - private final UserRepository userRepository; - - - public List getAllUsers() { - return userRepository.findAll(); - } - - public void deleteUserByEmail(String email) throws Exception { - - User userToDelete = userRepository.findByEmail(email) - .orElseThrow(() -> new UsernameNotFoundException("User not found.")); - - try { - - userRepository.deleteById(userToDelete.getId()); - - } catch (EmptyResultDataAccessException e) { - - throw new UsernameNotFoundException("User Deletion FAILED.", e); +public interface AdminService { - } + List getAllUsers(); - } + void deleteUserByEmail(String email); } diff --git a/src/main/java/com/alwinsimon/UserManagementJavaSpringBoot/Service/AuthenticationService.java b/src/main/java/com/alwinsimon/UserManagementJavaSpringBoot/Service/AuthenticationService.java index b85b0ee..2dcbfe0 100644 --- a/src/main/java/com/alwinsimon/UserManagementJavaSpringBoot/Service/AuthenticationService.java +++ b/src/main/java/com/alwinsimon/UserManagementJavaSpringBoot/Service/AuthenticationService.java @@ -3,73 +3,11 @@ import com.alwinsimon.UserManagementJavaSpringBoot.Config.Auth.AuthenticationRequest; import com.alwinsimon.UserManagementJavaSpringBoot.Config.Auth.AuthenticationResponse; import com.alwinsimon.UserManagementJavaSpringBoot.Config.Auth.RegisterRequest; -import com.alwinsimon.UserManagementJavaSpringBoot.Model.Role; -import com.alwinsimon.UserManagementJavaSpringBoot.Model.User; -import com.alwinsimon.UserManagementJavaSpringBoot.Repository.UserRepository; -import lombok.RequiredArgsConstructor; -import org.springframework.security.authentication.AuthenticationManager; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.core.userdetails.UsernameNotFoundException; -import org.springframework.security.crypto.password.PasswordEncoder; -import org.springframework.stereotype.Service; -@Service -@RequiredArgsConstructor -public class AuthenticationService { +public interface AuthenticationService { - private final UserRepository userRepository; - private final PasswordEncoder passwordEncoder; - private final JwtService jwtService; - private final AuthenticationManager authenticationManager; + AuthenticationResponse register(RegisterRequest request); - public AuthenticationResponse register(RegisterRequest request) { + AuthenticationResponse authenticate(AuthenticationRequest request); - // Build a user using builder in user model. - var user = User.builder() - .name(request.getName()) - .gender(request.getGender()) - .email(request.getEmail()) - .password(passwordEncoder.encode(request.getPassword())) - .role(Role.USER) - .build(); - - // Save User to DB using UserRepository - userRepository.save(user); - - // Generate a JWT Token to return along with Response. - var jwtToken = jwtService.generateJwtToken(user); - - return AuthenticationResponse.builder() - .token(jwtToken) - .build(); - - } - - public AuthenticationResponse authenticate(AuthenticationRequest request) { - - // Try Authenticating user with Authentication Manager - authenticationManager.authenticate( - new UsernamePasswordAuthenticationToken( - request.getEmail(), - request.getPassword() - ) - ); - - /** - * If the authentication manager authenticated user without throwing any exception - * Find user and generate auth token - * Send auth token back to user. - */ - - var user = userRepository.findByEmail(request.getEmail()) - .orElseThrow(() -> new UsernameNotFoundException("User not found.")); - - // Generate a JWT Token to return along with Response. - var jwtToken = jwtService.generateJwtToken(user); - - return AuthenticationResponse.builder() - .token(jwtToken) - .build(); - - } } diff --git a/src/main/java/com/alwinsimon/UserManagementJavaSpringBoot/Service/JwtService.java b/src/main/java/com/alwinsimon/UserManagementJavaSpringBoot/Service/JwtService.java index f1ccf07..f4a43fb 100644 --- a/src/main/java/com/alwinsimon/UserManagementJavaSpringBoot/Service/JwtService.java +++ b/src/main/java/com/alwinsimon/UserManagementJavaSpringBoot/Service/JwtService.java @@ -1,114 +1,21 @@ package com.alwinsimon.UserManagementJavaSpringBoot.Service; import io.jsonwebtoken.Claims; -import io.jsonwebtoken.Jwts; -import io.jsonwebtoken.SignatureAlgorithm; -import io.jsonwebtoken.io.Decoders; -import io.jsonwebtoken.security.Keys; import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.stereotype.Service; -import java.security.Key; -import java.util.Date; -import java.util.HashMap; import java.util.Map; import java.util.function.Function; -@Service -public class JwtService { +public interface JwtService { - // Set Signing Key for Signing JWT Tokens - private static final String JWT_SECRET_KEY = "2F66554775577754346D56726D7933315266773239773D3D"; + public String extractUsername(String jwtToken); - private Key getJwtSigningKey() { - // Function to provide JWT_SECRET_KEY + public T extractClaimFromJwtToken(String jwtToken, Function claimsResolver); - byte[] keyBytes = Decoders.BASE64.decode(JWT_SECRET_KEY); - return Keys.hmacShaKeyFor(keyBytes); + public String generateJwtToken(Map additionalClaims, UserDetails userDetails); - } + public String generateJwtToken(UserDetails userDetails); - public String extractUsername(String jwtToken) { - // Decrypt jwt token and return Username + public boolean isTokenValid(String jwtToken, UserDetails userDetails); - return extractClaimFromJwtToken(jwtToken, Claims::getSubject); - - } - - private Claims extractAllClaimsFromJwtToken(String jwtToken) { - // Function to Extract ALL claims from JWT Token - - return Jwts - .parserBuilder() - .setSigningKey(getJwtSigningKey()) - .build() - .parseClaimsJws(jwtToken) - .getBody(); - - } - - public T extractClaimFromJwtToken(String jwtToken, Function claimsResolver) { - // Function to Extract single claim from JWT Token - - final Claims claims = extractAllClaimsFromJwtToken(jwtToken); - return claimsResolver.apply(claims); - - } - - public String generateJwtToken(Map additionalClaims, UserDetails userDetails) { - /** - * Function to generate JWT Token With Additional Claims - */ - - return Jwts - .builder() - .setClaims(additionalClaims) - .setSubject(userDetails.getUsername()) - .setIssuedAt(new Date(System.currentTimeMillis())) - .setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 24)) // 24 hours - .signWith(getJwtSigningKey(), SignatureAlgorithm.HS256) - .compact(); - - } - - public String generateJwtToken(UserDetails userDetails) { - /** - * Function to generate JWT Token without any extra claims - * Internally uses generateJwtToken method which takes in additional claims - * In place of additional claims, passes an empty HashMap - */ - - return generateJwtToken(new HashMap<>(), userDetails); - - } - - public boolean isTokenValid(String jwtToken, UserDetails userDetails) { - /** - * Function to check the provided token is valid for the user and is not expired. - */ - - final String userName = extractUsername(jwtToken); - return (userName.equals(userDetails.getUsername()) && !isTokenExpired(jwtToken)); - - } - - private boolean isTokenExpired(String jwtToken) { - /** - * Function to check the provided token is valid for the user and is not expired. - */ - - return extractJwtTokenExpiration(jwtToken).before(new Date()); - - } - - private Date extractJwtTokenExpiration(String jwtToken) { - /** - * Function to return the expiration date of a provided Jwt Token - * Internally uses extractClaimFromJwtToken method which takes in token and a single required claim - * In place of single required claims, passes a claim to get expiration - */ - - return extractClaimFromJwtToken(jwtToken, Claims::getExpiration); - - } } diff --git a/src/main/java/com/alwinsimon/UserManagementJavaSpringBoot/Service/UserService.java b/src/main/java/com/alwinsimon/UserManagementJavaSpringBoot/Service/UserService.java index 2a82dfc..4297797 100644 --- a/src/main/java/com/alwinsimon/UserManagementJavaSpringBoot/Service/UserService.java +++ b/src/main/java/com/alwinsimon/UserManagementJavaSpringBoot/Service/UserService.java @@ -1,21 +1,10 @@ package com.alwinsimon.UserManagementJavaSpringBoot.Service; import com.alwinsimon.UserManagementJavaSpringBoot.Model.User; -import com.alwinsimon.UserManagementJavaSpringBoot.Repository.UserRepository; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; -import java.security.Principal; -@Service -@RequiredArgsConstructor -public class UserService { +public interface UserService { - private final UserRepository userRepository; - private final Principal principal; + public User currentUserDetails(); - public User currentUserDetails() { - String email = principal.getName(); - return userRepository.findByEmail(email).orElse(null); - } } From cfa3743ed7d6ae32a2e02187dac14d67cadfa138 Mon Sep 17 00:00:00 2001 From: "Dr. Alwin Simon" <003alwin@gmail.com> Date: Mon, 11 Dec 2023 12:19:58 +0530 Subject: [PATCH 8/8] Removed redundant access modifiers for Public interfaces. --- .../Service/JwtService.java | 10 +++++----- .../Service/UserService.java | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/alwinsimon/UserManagementJavaSpringBoot/Service/JwtService.java b/src/main/java/com/alwinsimon/UserManagementJavaSpringBoot/Service/JwtService.java index f4a43fb..683d29e 100644 --- a/src/main/java/com/alwinsimon/UserManagementJavaSpringBoot/Service/JwtService.java +++ b/src/main/java/com/alwinsimon/UserManagementJavaSpringBoot/Service/JwtService.java @@ -8,14 +8,14 @@ public interface JwtService { - public String extractUsername(String jwtToken); + String extractUsername(String jwtToken); - public T extractClaimFromJwtToken(String jwtToken, Function claimsResolver); + T extractClaimFromJwtToken(String jwtToken, Function claimsResolver); - public String generateJwtToken(Map additionalClaims, UserDetails userDetails); + String generateJwtToken(Map additionalClaims, UserDetails userDetails); - public String generateJwtToken(UserDetails userDetails); + String generateJwtToken(UserDetails userDetails); - public boolean isTokenValid(String jwtToken, UserDetails userDetails); + boolean isTokenValid(String jwtToken, UserDetails userDetails); } diff --git a/src/main/java/com/alwinsimon/UserManagementJavaSpringBoot/Service/UserService.java b/src/main/java/com/alwinsimon/UserManagementJavaSpringBoot/Service/UserService.java index 4297797..2b4e563 100644 --- a/src/main/java/com/alwinsimon/UserManagementJavaSpringBoot/Service/UserService.java +++ b/src/main/java/com/alwinsimon/UserManagementJavaSpringBoot/Service/UserService.java @@ -5,6 +5,6 @@ public interface UserService { - public User currentUserDetails(); + User currentUserDetails(); }