Custom annotation to check authorization in Spring
Tags: java, annotation, aspect, spring
Published: 2024-04-22 06:54:01

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.

```java

// 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.

```java
@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.