Skip to content

Commit

Permalink
Merge pull request #4 from MinhQuan992/booking-module-service
Browse files Browse the repository at this point in the history
feat: create spring security for booking service
  • Loading branch information
MinhQuan992 authored Sep 28, 2021
2 parents dee3394 + 18b9786 commit 34a49e7
Show file tree
Hide file tree
Showing 30 changed files with 453 additions and 48 deletions.
12 changes: 12 additions & 0 deletions .idea/inspectionProfiles/Project_Default.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 9 additions & 4 deletions booking/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,15 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</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-security</artifactId>
</dependency>
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.18.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
Expand Down
30 changes: 30 additions & 0 deletions booking/src/main/java/org/example/BookingApplication.java
Original file line number Diff line number Diff line change
@@ -1,12 +1,42 @@
package org.example;

import org.example.model.UserRole;
import org.example.model.UserAccount;
import org.example.service.UserService;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

import java.util.ArrayList;

@SpringBootApplication
public class BookingApplication
{
public static void main( String[] args ) {
SpringApplication.run(BookingApplication.class, args);
}

@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}

// @Bean
// CommandLineRunner run(UserService userService) {
// return args -> {
// userService.addRole(new UserRole(null, "ROLE_USER"));
// userService.addRole(new UserRole(null, "ROLE_ADMIN"));
//
// userService.addUser(new UserAccount(null, "Minh Quan", "minhquan", "1234", new ArrayList<>()));
// userService.addUser(new UserAccount(null, "Minh Hien", "minhhien", "1234", new ArrayList<>()));
// userService.addUser(new UserAccount(null, "Le Anh", "leanh", "1234", new ArrayList<>()));
//
// userService.addRoleToUser("minhquan", "ROLE_USER");
// userService.addRoleToUser("leanh", "ROLE_USER");
// userService.addRoleToUser("leanh", "ROLE_ADMIN");
// };
// }
}
40 changes: 10 additions & 30 deletions booking/src/main/java/org/example/controller/BookingController.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,21 +28,13 @@ public ResponseEntity<Iterable<Booking>> getAllBookings() {

@GetMapping("/{id}")
public ResponseEntity<Booking> getBookingById(@PathVariable("id") Long id) {
Optional<Booking> booking = bookingService.getBookingById(id);
if (booking.isEmpty()) {
throw new NotFoundException();
}
return new ResponseEntity<>(booking.get(), HttpStatus.OK);
return new ResponseEntity<>(bookingService.getBookingById(id), HttpStatus.OK);
}

@PostMapping
@PostMapping("/book")
public ResponseEntity<Booking> addNewBooking(
@RequestParam("roomId") Long roomId,
@RequestParam("customerName") String customerName) {
List<Long> bookedRooms = bookingService.getBookedRooms();
if (bookedRooms.contains(roomId)) {
throw new RoomUnavailableException();
}
LocalDate today = LocalDate.now();
Booking booking = new Booking(roomId, customerName, today, null, null);
return new ResponseEntity<>(bookingService.addNewBooking(booking), HttpStatus.CREATED);
Expand All @@ -54,13 +46,10 @@ public ResponseEntity<Booking> checkin(
@RequestParam("year") int year,
@RequestParam("month") int month,
@RequestParam("day") int day) {
Optional<Booking> booking = bookingService.getBookingById(id);
if (booking.isEmpty()) {
throw new NotFoundException();
}
Booking booking = bookingService.getBookingById(id);
LocalDate checkinDate = LocalDate.of(year, month, day);
booking.get().setCheckinDate(checkinDate);
return new ResponseEntity<>(bookingService.updateBooking(booking.get()), HttpStatus.OK);
booking.setCheckinDate(checkinDate);
return new ResponseEntity<>(bookingService.updateBooking(booking), HttpStatus.OK);
}

@PutMapping("/checkout/{id}")
Expand All @@ -69,24 +58,15 @@ public ResponseEntity<Booking> checkout(
@RequestParam("year") int year,
@RequestParam("month") int month,
@RequestParam("day") int day) {
Optional<Booking> booking = bookingService.getBookingById(id);
if (booking.isEmpty()) {
throw new NotFoundException();
}
Booking booking = bookingService.getBookingById(id);
LocalDate checkoutDate = LocalDate.of(year, month, day);
booking.get().setCheckoutDate(checkoutDate);
return new ResponseEntity<>(bookingService.updateBooking(booking.get()), HttpStatus.OK);
booking.setCheckoutDate(checkoutDate);
return new ResponseEntity<>(bookingService.updateBooking(booking), HttpStatus.OK);
}

@DeleteMapping("/{id}")
public ResponseEntity<Map<String, String>> deleteBooking(@PathVariable("id") Long id) {
Optional<Booking> booking = bookingService.getBookingById(id);
if (booking.isEmpty()) {
throw new NotFoundException();
}
bookingService.deleteBookingById(id);
Map<String, String> result = new HashMap<>();
result.put("Message: ", "Deleted Successfully");
return new ResponseEntity<>(result, HttpStatus.OK);
Booking booking = bookingService.getBookingById(id);
return new ResponseEntity<>(bookingService.deleteBooking(booking), HttpStatus.OK);
}
}
51 changes: 51 additions & 0 deletions booking/src/main/java/org/example/controller/UserController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package org.example.controller;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.example.model.RoleToUserForm;
import org.example.model.UserRole;
import org.example.model.UserAccount;
import org.example.service.UserService;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;

import java.net.URI;

@Slf4j
@RestController
@RequestMapping("api")
@AllArgsConstructor
public class UserController {
private final UserService userService;

@GetMapping("/users")
public ResponseEntity<Iterable<UserAccount>> getAllUsers() {
return new ResponseEntity<>(userService.getAllUsers(), HttpStatus.OK);
}

@GetMapping("/user/{username}")
public ResponseEntity<UserAccount> getUserByUsername(@PathVariable("username") String username) {
return new ResponseEntity<>(userService.getUserByUsername(username), HttpStatus.OK);
}

@PostMapping("/user/save")
public ResponseEntity<UserAccount> saveUser(@RequestBody UserAccount userAccount) {
URI uri = URI.create(ServletUriComponentsBuilder.fromCurrentContextPath().path("/api/user/save").toUriString());
return ResponseEntity.created(uri).body(userService.addUser(userAccount));
}

@PostMapping("/role/save")
public ResponseEntity<UserRole> saveRole(@RequestBody UserRole userRole) {
URI uri = URI.create(ServletUriComponentsBuilder.fromCurrentContextPath().path("/api/role/save").toUriString());
return ResponseEntity.created(uri).body(userService.addRole(userRole));
}

@PostMapping("/role/addtouser")
public ResponseEntity<?> addRoleToUser(@RequestBody RoleToUserForm roleToUserForm) {
userService.addRoleToUser(roleToUserForm.getUsername(), roleToUserForm.getRoleName());
return ResponseEntity.ok().build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package org.example.filter;

import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
public class CustomAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
private final AuthenticationManager authenticationManager;

public CustomAuthenticationFilter(AuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
}

@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
String username = request.getParameter("username");
String password = request.getParameter("password");
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, password);
return authenticationManager.authenticate(authenticationToken);
}

@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
User user = (User) authResult.getPrincipal();
Algorithm algorithm = Algorithm.HMAC256("secret".getBytes());
String access_token = JWT.create()
.withSubject(user.getUsername())
.withExpiresAt(new Date(System.currentTimeMillis() + 100 * 60 * 1000))
.withIssuer(request.getRequestURL().toString())
.withClaim("roles", user.getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.toList()))
.sign(algorithm);

Map<String, String> token = new HashMap<>();
token.put("access_token", access_token);
response.setContentType("application/json");
new ObjectMapper().writeValue(response.getOutputStream(), token);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package org.example.filter;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import static java.util.Arrays.stream;
import static org.springframework.http.HttpHeaders.*;
import static org.springframework.http.HttpStatus.FORBIDDEN;
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;

@Slf4j
public class CustomAuthorizationFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
if (request.getServletPath().equals("/api/login")) {
filterChain.doFilter(request, response);
} else {
String authorizationHeader = request.getHeader(AUTHORIZATION);
if (authorizationHeader != null && authorizationHeader.startsWith("Bearer")) {
try {
String token = authorizationHeader.substring("Bearer ".length());
Algorithm algorithm = Algorithm.HMAC256("secret".getBytes());
JWTVerifier verifier = JWT.require(algorithm).build();
DecodedJWT decodedJWT = verifier.verify(token);

String username = decodedJWT.getSubject();
String[] roles = decodedJWT.getClaim("roles").asArray(String.class);

Collection<SimpleGrantedAuthority> authorities = new ArrayList<>();
stream(roles).forEach(role -> {
authorities.add(new SimpleGrantedAuthority(role));
});

UsernamePasswordAuthenticationToken authenticationToken =
new UsernamePasswordAuthenticationToken(username, null, authorities);
SecurityContextHolder.getContext().setAuthentication(authenticationToken);

filterChain.doFilter(request, response);
} catch (Exception exception) {
response.setHeader("Error", exception.getMessage());
response.setStatus(FORBIDDEN.value());

Map<String, String> errors = new HashMap<>();
errors.put("error_message", exception.getMessage());
response.setContentType(APPLICATION_JSON_VALUE);
new ObjectMapper().writeValue(response.getOutputStream(), errors);
}
} else {
filterChain.doFilter(request, response);
}
}
}
}
9 changes: 9 additions & 0 deletions booking/src/main/java/org/example/model/RoleToUserForm.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package org.example.model;

import lombok.Data;

@Data
public class RoleToUserForm {
private String username;
private String roleName;
}
24 changes: 24 additions & 0 deletions booking/src/main/java/org/example/model/UserAccount.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package org.example.model;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import javax.persistence.*;
import java.util.ArrayList;
import java.util.Collection;

@Entity
@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserAccount {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
private String username;
private String password;
@ManyToMany(fetch = FetchType.EAGER)
private Collection<UserRole> userRoles = new ArrayList<>();
}
21 changes: 21 additions & 0 deletions booking/src/main/java/org/example/model/UserRole.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package org.example.model;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserRole {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,5 @@
import java.util.List;

public interface BookingRepository extends JpaRepository<Booking, Long> {
@Query("SELECT b.roomId FROM Booking b WHERE b.checkoutDate IS NULL")
List<Long> findBookedRooms();
List<Booking> findBookingsByCheckoutDateIsNull();
}
Loading

0 comments on commit 34a49e7

Please sign in to comment.