I have several controller functions separated by role, and instead of doing role validation in each controller method, I found that it seems to be able to get done by using Aspect, however something isn't right in my implementation as the code in Aspect never runs
Annotation:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ForMerchantOnly {}
Aspect:
@Aspect
@Configuration
public class ForMerchantOnlyAspect {
private static final Logger logger = LogManager.getLogger(ForMerchantOnlyAspect.class);
@Before("@annotation(com.example.api.annotation.ForMerchantOnly) && args(request)")
public void before(HttpServletRequest request) throws ServiceException {
if (!(request instanceof HttpServletRequest)) {
throw new RuntimeException("request should be HttpServletRequesttype");
}
String domain = request.getServerName();
System.out.println("Aspect showing domain " + domain);
// -- other code
}
}
Controller
@ForMerchantOnly
@GetMapping("/list")
public ResponseEntity<ApiResp> list() {
System.out.println("Show something");
return ResponseEntity.ok().body();
}
I'm assuming when i call controller /list method via chrome browser, it would hit the code in ForMerchantOnlyAspect
but it just went into the controller method directly. Am I missing something?
The Aspect was not working as it could not find a matching joinpoint . There are no controller methods that has annotation @ForMerchantOnly
and has an argument of type HttpServletRequest
From the documentation :
args: Limits matching to join points (the execution of methods when using Spring AOP) where the arguments are instances of the given types.
Following aspect may be used for the requirement . Scoping designator within
will set the scope to advice.
@Before("@annotation(com.example.api.annotation.ForMerchantOnly) && within(com.example.api..*)")
public void before() {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes())
.getRequest();
System.out.println("Aspect showing domain " + request.getServerName());
}
Also note that an Aspect is better annotated with @Component
and @Configuration
be used for configurations.
You may also have a look at Method Security of Spring security framework , which lets to secure a method with annotations.
From the documentation
From version 2.0 onwards Spring Security has improved support substantially for adding security to your service layer methods. It provides support for JSR-250 annotation security as well as the framework’s original @Secured annotation. From 3.0 you can also make use of new expression-based annotations. You can apply security to a single bean, using the intercept-methods element to decorate the bean declaration, or you can secure multiple beans across the entire service layer using the AspectJ style pointcuts.