Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added security management and user management related sample files. #12

Merged
merged 9 commits into from
Mar 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 21 additions & 5 deletions pom.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
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">
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">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
Expand Down Expand Up @@ -37,6 +36,10 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency> -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
Expand Down Expand Up @@ -76,21 +79,34 @@
<version>3.25.3</version>
<scope>test</scope>
</dependency>
<!-- <dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency> -->
<!-- <dependency>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
<version>4.0.2</version>
</dependency> -->
</dependencies>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<!-- <configuration>
<image>
<builder>paketobuildpacks/builder-jammy-base:latest</builder>
</image>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</configuration> -->
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
Expand All @@ -99,4 +115,4 @@
</plugins>
</pluginManagement>
</build>
</project>
</project>
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
@@ -0,0 +1,15 @@
package sg.com.smartinventory.entities;

import java.time.LocalDateTime;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
@AllArgsConstructor
public class ErrorResponse {
private String message;
private LocalDateTime timestamp;
}
69 changes: 69 additions & 0 deletions src/main/java/sg/com/smartinventory/entities/User.java.dev
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package sg.com.smartinventory.entities;

import java.util.List;

import jakarta.persistence.CascadeType;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.JoinTable;
import jakarta.persistence.ManyToMany;
import jakarta.persistence.Table;
import jakarta.validation.constraints.Digits;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Getter
@Setter
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Entity
@Table(name = "my_user")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Long id;

@NotBlank(message = "Username cannot be blank")
@Column(name = "username")
private String username;

@NotBlank(message = "Password cannot be blank")
@Column(name = "password")
private String password;

@NotBlank(message = "First name cannot be blank")
@Column(name = "first_name")
private String firstName;

@Column(name = "last_name")
private String lastName;

@Digits(fraction = 0, integer = 8, message = "ContactNo must be 8 digits")
@Column(name = "contact_no")
private String contactNo;

@Email(message = "Email format must be valid")
@Column(name = "email")
private String email;

@ManyToMany(cascade = CascadeType.ALL)
@JoinTable(name = "user_user_role", joinColumns = { @JoinColumn(name = "user_id") }, inverseJoinColumns = {
@JoinColumn(name = "user_role_id") })
private List<UserRole> roles;

public User(String email) {
this.email = email;
}
}
Loading