Skip to content

Commit

Permalink
Added security management and user management related sample files.
Browse files Browse the repository at this point in the history
Appended with .dev to not affect build and test execution. KIV.
  • Loading branch information
nhkhai committed Mar 23, 2024
1 parent f0493eb commit fc7b698
Show file tree
Hide file tree
Showing 22 changed files with 500 additions and 5 deletions.
8 changes: 4 additions & 4 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,10 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<!-- <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
</dependency> -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
Expand Down Expand Up @@ -79,11 +79,11 @@
<version>3.25.3</version>
<scope>test</scope>
</dependency>
<dependency>
<!-- <dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
</dependency> -->
<!-- <dependency>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package sg.com.smartinventory.controllers;

import org.springframework.web.bind.annotation.RestController;

import sg.com.smartinventory.entities.LoginRequest;
import sg.com.smartinventory.entities.User;
import sg.com.smartinventory.security.JwtTokenUtil;

import org.springframework.http.HttpStatus;
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.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;

@RestController
@RequestMapping("/auth/")
public class AuthController {
private final AuthenticationManager authenticationManager;

private JwtTokenUtil jwtTokenUtil;

public AuthController(AuthenticationManager authenticationManager, JwtTokenUtil jwtTokenUtil) {
this.authenticationManager = authenticationManager;
this.jwtTokenUtil = jwtTokenUtil;
}

@PostMapping("/login")
public ResponseEntity<String> login(@RequestBody LoginRequest login) {
Authentication auth = authenticationManager
.authenticate(new UsernamePasswordAuthenticationToken(login.getUsername(), login.getPassword()));

String email = auth.getName();

String token = jwtTokenUtil.createToken(new User(email));

return new ResponseEntity<>(token, HttpStatus.OK);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package sg.com.smartinventory.controllers;

import java.time.LocalDateTime;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

import sg.com.smartinventory.entities.ErrorResponse;
import sg.com.smartinventory.exceptions.UserNotFoundException;
import sg.com.smartinventory.exceptions.UserRoleNotFoundException;

@ControllerAdvice
public class GlobalExceptionHandler {
private Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);

@ExceptionHandler({ UserNotFoundException.class, UserRoleNotFoundException.class })
public ResponseEntity<ErrorResponse> handleResourceNotFoundException(Exception ex) {
return new ResponseEntity<>(new ErrorResponse(ex.getMessage(), LocalDateTime.now()), HttpStatus.NOT_FOUND);
}

@ExceptionHandler(EmptyResultDataAccessException.class)
public ResponseEntity<ErrorResponse> handleEmptyResultDataAccessException(EmptyResultDataAccessException ex) {
ErrorResponse errorResponse = new ErrorResponse("Resource does not exist.", LocalDateTime.now());

return new ResponseEntity<>(errorResponse, HttpStatus.NOT_FOUND);
}

@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ErrorResponse> handleValidationExceptions(MethodArgumentNotValidException ex) {
// Get a list of all validation errors from the exception object
List<ObjectError> validationErrors = ex.getBindingResult().getAllErrors();

// Create a StringBuilder to store all error messages
StringBuilder sb = new StringBuilder();

for (ObjectError error : validationErrors) {
sb.append(error.getDefaultMessage() + ". ");
}

ErrorResponse errorResponse = new ErrorResponse(sb.toString(), LocalDateTime.now());

return new ResponseEntity<>(errorResponse, HttpStatus.BAD_REQUEST);
}

@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleException(Exception ex) {
logger.error("Unknown Exception occured!", ex);

ErrorResponse errorResponse = new ErrorResponse("Something went wrong. ", LocalDateTime.now());

return new ResponseEntity<>(errorResponse, HttpStatus.INTERNAL_SERVER_ERROR);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package sg.com.smartinventory.controllers;

import java.util.List;

import jakarta.validation.Valid;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import sg.com.smartinventory.entities.User;
import sg.com.smartinventory.services.UserService;

@RestController
@RequestMapping("/users")
public class UserController {
private UserService userService;

public UserController(UserService userService) {
this.userService = userService;
}

@GetMapping("")
public ResponseEntity<List<User>> getAllUsers() {
return new ResponseEntity<>(userService.getAllUsers(), HttpStatus.OK);
}

@GetMapping("/{id}")
public ResponseEntity<User> getOneUser(@PathVariable Long id) {
return new ResponseEntity<>(userService.getOneUser(id), HttpStatus.OK);
}

@PostMapping("")
public ResponseEntity<User> createUser(@Valid @RequestBody User user) {
return new ResponseEntity<>(userService.createUser(user), HttpStatus.CREATED);
}

@PutMapping("/{id}")
public ResponseEntity<User> updateUser(@PathVariable Long id, @Valid @RequestBody User user) {
return new ResponseEntity<>(userService.updateUser(id, user), HttpStatus.OK);
}

@DeleteMapping("/{id}")
public ResponseEntity<User> deleteUser(@PathVariable Long id) {
userService.deleteUser(id);
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}

@PutMapping("/{id}/userrole/{roleId}")
public ResponseEntity<User> addUserRoleToUser(@PathVariable(name = "id") Long userId, @PathVariable Long roleId) {
return new ResponseEntity<>(userService.addUserRoleToUser(userId, roleId), HttpStatus.OK);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package sg.com.smartinventory.controllers;

import java.util.List;

import jakarta.validation.Valid;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import sg.com.smartinventory.entities.UserRole;
import sg.com.smartinventory.services.UserRoleService;

@RestController
@RequestMapping("/userroles")
public class UserRoleController {
private UserRoleService userRoleService;

public UserRoleController(UserRoleService userRoleService) {
this.userRoleService = userRoleService;
}

@GetMapping("")
public ResponseEntity<List<UserRole>> getAllUsers() {
return new ResponseEntity<>(userRoleService.getAllUserRoles(), HttpStatus.OK);
}

@GetMapping("/{id}")
public ResponseEntity<UserRole> getOneUser(@PathVariable Long id) {
return new ResponseEntity<>(userRoleService.getOneUserRole(id), HttpStatus.OK);
}

@PostMapping("")
public ResponseEntity<UserRole> createUser(@Valid @RequestBody UserRole role) {
return new ResponseEntity<>(userRoleService.createUserRole(role), HttpStatus.CREATED);
}

@PutMapping("/{id}")
public ResponseEntity<UserRole> updateUser(@PathVariable Long id, @Valid @RequestBody UserRole role) {
return new ResponseEntity<>(userRoleService.updateUserRole(id, role), HttpStatus.OK);
}

@DeleteMapping("/{id}")
public ResponseEntity<UserRole> deleteUser(@PathVariable Long id) {
userRoleService.deleteUserRole(id);
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}

@PutMapping("/{id}/user/{userId}")
public ResponseEntity<UserRole> putMethodName(@PathVariable Long id, @PathVariable Long userId) {
return new ResponseEntity<>(userRoleService.addUserToUserRole(id, userId), HttpStatus.OK);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

@ControllerAdvice
public class GlobalExceptionHandler {
// This is handler for CustomerNotFoundException
// This is handler for CustomerNotFoundException.
@ExceptionHandler({ CustomerNotFoundException.class, ProductNotFoundException.class,
ReviewNotFoundException.class })
public ResponseEntity<ErrorResponse> handleResourceNotFoundException(CustomerNotFoundException ex) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package sg.com.smartinventory.exceptions;

public class UserNotFoundException extends RuntimeException {
public UserNotFoundException(Long id) {
super("User with id: " + id + " cannot be found. ");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package sg.com.smartinventory.exceptions;

public class UserRoleNotFoundException extends RuntimeException {
public UserRoleNotFoundException(Long id) {
super("User role with id: " + id + " cannot be found. ");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package sg.com.smartinventory.repositories;

import org.springframework.data.jpa.repository.JpaRepository;

import sg.com.smartinventory.entities.UserRole;

public interface UserRoleRepository extends JpaRepository<UserRole, Long> {

}
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,17 @@ public CustomUserDetailsService(UserRepository userRepository) {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findByUsername(username);

List<String> roles = new ArrayList<>();

roles.add("USER");

UserDetails userDetails = org.springframework.security.core.userdetails.User.builder()
.username(user.getUsername())
.password(user.getPassword())
.roles(roles.toArray(new String[0]))
.build();

return userDetails;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package sg.com.smartinventory.serviceImpls;

import java.util.List;

import javax.annotation.PostConstruct;

import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;

import sg.com.smartinventory.entities.User;
import sg.com.smartinventory.entities.UserRole;
import sg.com.smartinventory.repositories.UserRepository;
import sg.com.smartinventory.repositories.UserRoleRepository;

@Component
public class UserDataLoader {
private UserRepository userRepository;
private UserRoleRepository userRoleRepository;
private PasswordEncoder encoder;

public DataLoader(UserRepository userRepository, UserRoleRepository userRoleRepository, PasswordEncoder encoder) {
this.userRepository = userRepository;
this.userRoleRepository = userRoleRepository;
this.encoder = encoder;
}

@PostConstruct
public void preLoadData() {
// Check if there's any record inside the database.
if (userRepository.count() == 0 && userRoleRepository.count() == 0) {
userRepository.save(User.builder()
.username("IronMan")
.firstName("Tony")
.lastName("Stark")
.contactNo("22310091")
.email("[email protected]")
.password(encoder.encode("Iamironman"))
.build());

userRepository.save(User.builder()
.username("CaptainAmerica")
.firstName("Steve")
.lastName("Roger")
.contactNo("11215542")
.email("[email protected]")
.password(encoder.encode("Icandothisallday"))
.build());

userRoleRepository.save(UserRole.builder()
.roleName("Admin")
.description("Administrator")
.build());

userRoleRepository.save(UserRole.builder()
.roleName("User")
.description("System User")
.build());

List<User> users = userRepository.findAll();
List<UserRole> roles = userRoleRepository.findAll();

for (User user : users) {
user.setRoles(roles);
}

userRepository.saveAll(users);
}
}
}
Loading

0 comments on commit fc7b698

Please sign in to comment.