Limiting access to the data of other users

Now, this is a little more tricky, as this requires us to change code at the service layer on the backend, but it is not hard. Let's get right to it.

Let's start with the product order entity. Modify the findAll method in src/main/java/com/mycompany/store/service/ProductOrderService.java as follows:

    @Transactional(readOnly = true)
public Page<ProductOrder> findAll(Pageable pageable) {
log.debug("Request to get all ProductOrders");
if (SecurityUtils.isCurrentUserInRole
(AuthoritiesConstants.ADMIN)) {

return productOrderRepository.findAll(pageable);
} else
return productOrderRepository.findAllByCustomerUserLogin(
SecurityUtils.getCurrentUserLogin().get(),
pageable
);
}

As you can see, we modified the original call to productOrderRepository.findAll(pageable) so that we call it only when the current user has the Admin role; otherwise, we call findAllByCustomerUserLogin, but our generated ProductOrderRepository interface does not have this method yet, so let's add that. In src/main/java/com/mycompany/store/repository/ProductOrderRepository.java, let's add a new method as follows. Currently, the interface doesn't have any methods and only uses methods inherited from JpaRepository:

Page<ProductOrder> findAllByCustomerUserLogin(String login, Pageable pageable);

There is a lot of magic going on here. This is a Spring Data interface, and so we can simply write a new method and expect Spring Data to create an implementation for this automatically; we just need to follow the naming conventions. In our use case, we need to find all product orders where the user relationship for the customer has the same login as our current logged in user. In SQL, this would be as follows:

select * from product_order po cross join customer c cross join jhi_user u where po.customer_id=c.id and c.user_id=u.id and u.login=:login

In simple terms, we could say find all product orders where customer.user.login equals login, and that is exactly what we have written as the findAllByCustomerUserLogin method. The entity under operation is implicit, and so the product order is omitted. By providing the Pageable parameter, we tell Spring Data to provide us a page from the paginated list of entities. You can refer to the Spring Data documentation at https://docs.spring.io/spring-data/jpa/docs/current/reference/html/ for more information.

While calling the productOrderRepository.findAllByCustomerUserLogin method, we can pass the current user login using the SecurityUtils.getCurrentUserLogin() method. The SecurityUtils class is generated by JHipster as well, as it has useful methods such as getCurrentUserLogingetCurrentUserJWTisAuthenticated, and isCurrentUserInRole.

That's it. Now log in as admin and create two new users and two customers, and create product orders for each of them. Then log out and log in again as the default user and see whether you can see the product order for one of the newly created users.

Now let's make similar updates for the other services. Note that each method is slightly different based on the relationships between the entities. The repository methods for these would be as follows:

For src/main/java/com/mycompany/store/repository/InvoiceRepository:

Page<Invoice> findAllByOrderCustomerUserLogin(String login, Pageable pageable);

For src/main/java/com/mycompany/store/repository/OrderItemRepository:

Page<OrderItem> findAllByOrderCustomerUserLogin(String login, Pageable pageable);

For src/main/java/com/mycompany/store/repository/ShipmentRepository:

Page<Shipment> findAllByInvoiceOrderCustomerUserLogin(String login, Pageable pageable);

Now we need to make similar changes to the findOne method on the services.

For ProductOrderService, these would be as follows:

    @Transactional(readOnly = true)
public ProductOrder findOne(Long id) {
log.debug("Request to get ProductOrder : {}", id);
if (SecurityUtils.isCurrentUserInRole
(AuthoritiesConstants.ADMIN)) {

return productOrderRepository.findById(id);
} else
return productOrderRepository.
findOneByIdAndCustomerUserLogin(

id,
SecurityUtils.getCurrentUserLogin().get()
);
}

As you can see, we changed the methods to find one by its ID and customer user login. The repository method for this would be as follows:

Optional<ProductOrder> findOneByIdAndCustomerUserLogin(Long id, String login);

For src/main/java/com/mycompany/store/repository/InvoiceRepository:

Optional<Invoice> findOneByIdAndOrderCustomerUserLogin(Long id, String login);

For src/main/java/com/mycompany/store/repository/OrderItemRepository:

Optional<OrderItem> findOneByIdAndOrderCustomerUserLogin(Long id, String login);

For src/main/java/com/mycompany/store/repository/ShipmentRepository:

Optional<Shipment> findOneByIdAndInvoiceOrderCustomerUserLogin(Long id, String login);

The same queries can also be written using the @Query annotation provided by Spring Data.

Now change the findOne method for other entities as well, and that's it. We have implemented a good role-based authorization logic for the application.

Let's commit this checkpoint:

> git add --all
> git commit -am "update role based authorization logic"

In a real-world scenario, the changes we have made so far will not be enough for an e-commerce website. But since our aim is to learn JHipster and its supported tools rather than to create a feature-perfect application, consider this a minimum-viable product. To make this e-commerce application usable, we would need to build more features, such as a shopping cart, invoice generation, customer registration, and so on. Why don't you take these exercises up as assignments and see whether you can build more features for this application? This would be part of the next steps to take once you finish the book. The use case and instructions will be described in Chapter 15, Best Practices with JHipster.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.16.66.206