Custom annotation to check authorization in Spring
Luciano Pinheiro
Posted on April 22, 2024
In Spring, we have the ability to apply custom annotations to methods, classes, or fields, in order to execute specific actions before or after the annotated object. This is achieved through Aspect-Oriented Programming (AOP).
To implement this solution, we need to create both a custom annotation and a method that will be triggered when the application encounters the annotation. Annotations serve as markers, indicating a specific point in the code, and in order to perform an action, we need to associate that marker with a method from a designated class. Therefore, creating a custom annotation also involves creating an Aspect class/method.
For example, let's consider an annotation that verifies if a person has a particular role. This annotation can be used within methods in a Spring Controller.
Annotation @VerifyAuthorization
To create an annotation, you need to use the syntax below. Please notice:
- Use @interface to define the annotation
- Use @Retention to choose the policy (usually RUNTIME)
- Use @Target to specify the element type (TYPE for class, METHOD, or FIELD)
To create an annotation with parameters, we need to define them as the syntax below.
// define annotation
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface VerifyAuthorization {
String value() default "";
}
// use in a controller method
@RestController
public class ThisController {
@VerifyAuthorization("boss")
public String save () {...}
}
Aspect Method
With Aspect, we can intercept virtually any call in Java. There are two frameworks for this: Spring AOP and AspectJ. While AspectJ is more flexible, it is also more complex.
To intercept the annotation and execute a specific method before (or after or around) the annotated target, we define what is called advice.
Firstly, we need to install spring-boot-starter-aop
if using Spring Boot or AOP
and AspectJ
if using Spring. There is a trick. AspectJ doesn't search targets automatically. So, we need to enable this feature in a XML or annotation format.
After all installations and configurations are completed, we can create a method and link it to the annotation.
Notice in the syntax:
- @Aspect annotation for the aspect class
- @Component to make it unique
- @Before (or @After or @Around) annotation indicating the annotation
- JoinPoint holds the method information
Inside the method, we use some objects to access the annotated method and its parameters.
@Aspect
@Component
public class VerifyAuthorizationAdvice {
@Before("@annotation(com.example.VerifyAuthorization)")
public void beforeAnnotation(JoinPoint joinPoint){
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
VerifyAuthorization annotation = signature.getMethod().getAnnotation(VerifyAuthorization.class);
CustomUserSecurity.hasRole(annotation.value());
}
}
The VerifyAuthorizationAdvice
class can include any necessary logic or dependency. In the example, @Before is used to run the method before the annotated one. If an exception is thrown, the original method will not be executed. Alternativelly, @After could be used to run it after the original method, or @Around to replace it. When using @Around, we can control when the original method is executed by calling joinPoint.proceed();
at some point within our advice method.
Posted on April 22, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.