SpringBoot: Embrace AOP For Authorizing API Requests

George Berar
4 min readNov 22, 2021

--

In today’s article I will talk about how to leverage Spring AOP in order to authorize API requests at endpoint level.

Disclaimer: The purpose of this article is to give you a practical example of using AOP and not to explain in details all concepts.

Background

Let’s suppose we build an API to track monthly expenses which has Spring Security with basic auth enabled and we want to authorize the requests based on the authorities of the authenticated user.

As a short parenthesis, authentication is the process of validating user’s identity to determine they are who they claim to be and authorization is the process of validating the user’s permissions/roles/rights in order to access a specific resource.

For simplicity we have only two authorities: USER and ADMIN and we can consider the authentication process already populates the Spring Security Context with correct granted authorities based on username/password combination.

Our custom security authorities

The Problem

Some of our API’s endpoints require USER authority and others require the ADMIN one (for user management and other administrative requirements).

How can we achieve authorization for our custom authorities?

The Out-of-the-box Solution

With Spring we can use the well known @PreAuthorize annotation at endpoint level:

Example use of @PreAuthorize annotation with plain text

As you can see we specify the hasAuthority('USER') as value for the @PreAuthorize annotation which translates to: the authenticated user must have the USER authority in order to access this endpoint. If this authority is missing then 403 Forbidden will be returned.

The main issue with specifying the authority value as plain text is the maintainability and the fact that is prone to typos and breaking changes. Imagine we want to refactor the authority name from USER to CUSTOMER in SecurityAuthorities…this means you need to make sure you find all places where 'USER' string is found and replace it with 'CUSTOMER'; add the fact that you need to do it in 25 different places and it quickly becomes a pain. So why not using our enum class instead?

Example use of @PreAuthorize annotation with enum class

Using the enum class is a little bit easier than plain text because at compile time you can put the correct value after the fully qualified package name and you don’t need to bother with typos. Also, if you rename the authority name or move the enum in another package the changes will be reflected here…BUT if you delete the enum the compiler will not complain at all and this is a big issue because it hides the fact your endpoint is expecting an authority or authorities which don’t exist anymore.

Even if the @PreAuthorize annotation solves the authorization process and it’s pretty straightforward to use we still need a cleaner and more maintainable solution in order to use our enum values directly without qualifying package names or hardcoded strings and at the same time to be compile time safe. AOP comes to the rescue!

The AOP Solution

What is AOP

Aspect-Oriented Programming (AOP) complements Object-Oriented Programming (OOP) by providing another way of thinking about program structure. The key unit of modularity in OOP is the class, whereas in AOP the unit of modularity is the aspect. Aspects enable the modularization of concerns such as transaction management that cut across multiple types and objects. — by Spring Docs

Image credits SayingImages

I know the definition given by Spring Docs can be a little hard to grasp on but long story short AOP allows you to add additional behavior to existing code without modifying the code itself.

What we will do basically is to implement a method which will be invoked by AOP automatically whenever a new request comes to our endpoint and which receives a set of authorities to check against the authenticated user (the Principal) in order to decide the outcome of the authorization. Keep in mind the existing code for our endpoint will suffer one minor change only: replacing the @PreAuthorize annotation with a custom one. Let’s proceed…

Custom Annotation

First, we need a way to specify which subset of our custom authorities does the endpoint need to check. For this we will create a custom annotation to work directly with our enum and not strings anymore:

Next we need to update our endpoint(s) as follows:

Specify the required authorities using the custom annotation

The nice thing about this custom annotation is that in case we refactor our SecurityAuthorities enum all changes will be reflected immediately and in case we delete it the compiler will scream.

AOP Method

After we defined our custom annotation we need to create the method that will be invoked on each request targeting one of our endpoints annotated with @HasEndpointAuthorities .

Notice the @Aspect annotation at class level and @Before annotation at method level. The first one marks the class to be used by Spring AOP and the second one is translated as follows: invoke hasAuthorities method before each method call annotated with @HasEndpointAuthorities which is part of a class annotated with @RestController only. So whenever a request comes to our /api/v1/expenses endpoint, the hasAuthorities method will be automatically invoked before the actual call to the getExpenses method. If hasAuthorities throws an exception (403 Forbidden) then getExpenses will not be invoked anymore and the 403 response will be automatically returned.

That’s it! You can control now which authorities to check for each endpoint by simply using one line of code via the custom annotation and you can fully benefit of the enum class also.

Conclusion

As always please keep in mind this approach might or might not suit your project context or needs and I’m not in the position to say there’s no other way to do it differently or better. I really hope you enjoyed it and had fun reading it.

--

--

George Berar

Senior Software Engineer • Freelancer • Tech Enthusiast