bookmark_borderAspect Oriented Programming for authorization in Spring

Spring AOP, or Aspect-Oriented Programming, is a framework within the Spring Framework that enables modularization of cross-cutting concerns in Java applications. It allows developers to separate concerns like logging, security, and transaction management from the core business logic. AOP achieves this by introducing aspects, which are modules encapsulating cross-cutting concerns, and weaving them into the application at specified points. This helps in achieving better code modularity, reusability, and maintainability by reducing code duplication and promoting a cleaner architecture.

In this article we will show you how to utilize AOP for authorization.

This is a database table which contains products:

IDTitleQuantityTenantID
1Product 1402
2Product 2502
3Product 32010

ProductService class contains a method for product deletion:

This service method is exposed trough REST API call which accepts ID parameter and calls the method which deletes product.

JWT of authenticated user contains its own tenant ID which is 2 in current example. So user should only be allowed to delete product 1 and product 2. Deletion attempt of product 3 should generate 403 forbidden.

We will create an annotation which should be placed before each protected method.

Next class we need is an aspect

Finally we are going to annotate a protected method from service

Order of actions

  • @ProductPermission annotation triggers ProductPermissionAspect.check method execution before each call of annotated method
  • ProductPermissionAspect grabs first parameter of a target method call which is product ID
  • ProductPermissionAspect checks if the product belongs to tenant of an authenticated user
  • ProductPermissionAspect generates 403 forbidden if the product doesn’t belong to the user

If you want to deep dive into more details:

https://docs.spring.io/spring-framework/reference/core/aop.html

https://www.baeldung.com/spring-aop

bookmark_borderMariaDB recursive query

Database table org_structure stores an organizational structure nested hierarchy. It starts from the root (CEO) which has parent_id NULL.

idtitleparent_id
1CEONULL
2Director 11
3Director 21
4Manager 12
5Manager 22
6Manager 33
7Manager 43
8OP 14
9OP 24
10OP 35
11OP 45
12OP 56
13OP 66
14OP 77
15OP 87

This is a graphical representation of org_structure database table.

Let us take an example that we want to select “Director 2” and every descendant in the hierarchy. So result will include (Director 2, Manager 3, Manager 4, OP 5 – 8).

MariaDB provides elegant solution for this problem (recursive queries).

Result:

3 Director 2
6 Manager 3
7 Manager 4
12 OP 5
13 OP 6
14 OP 7
15 OP 8

Detailed explanation can be found on following link:
https://mariadb.com/kb/en/recursive-common-table-expressions-overview/

bookmark_borderSpring boot dependency injection using @ConditionalOnProperty annotation

Suppose that you have a webshop with a credit card payment option. Credit card payments work fine in a production environment. There is a new requirement to implement a sandbox environment for the webshop. Sandbox environment doesn’t charge your credit card. It always returns a successful response.

Each checkout implementation is based on the following CheckoutService interface:

The implementation of CheckoutService an interface for the production environment is BankCheckoutService

CheckoutController gets instance of CheckoutService using @Autowired annotation (dependency injection).

Let us create a new implementation of CheckoutService interface for the sandbox environment:

It will work fine if we replace a constructor of CheckoutController to get SandboxCheckoutService bean:

However, we want to instantiate either BankCheckoutService or SandboxCheckoutService based on the variable in the application properties file. SandboxCheckoutService should be instantiated if application properties contains the following content:

If sandbox the variable is false BankCheckoutService will be instantiated.

Spring Boot already has a solution. @ConditionalOnProperty annotation provides us the possibility to conditionally instantiate bean based on property value from application.properties file.

BankCheckoutService:

SandboxCheckoutService

The controller doesn’t have to be changed since it expects CheckoutService interface which is implemented in both BankCheckoutService and SandboxCheckoutService. Controller depends on abstraction not implementation as it is specified in SOLID principle.

We can now switch between BankCheckoutService and SandboxCheckoutService by changing the sandbox variable in the application.properties file.