My goal is to create such annotation instead of standard way:
@RequiresAnyRole({"UPDATE_DATA"})
@PreAuthorize("hasAnyAuthority('UPDATE_DATA')")
If I succeed, this will open a path to creating business security annotations, which you can eventually override at a method level.
I am using Spring Boot 3.3 at this moment.
My annotation is this:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@PreAuthorize("@securityHelper.hasAnyListedAuthority(authentication, #root.annotation.value)")
public @interface RequiresAnyRole {
String[] value() default {};
}
But it failed with:
EL1008E: Property or field 'annotation' cannot be found on object of type '.springframework.security.access.expression.method.MethodSecurityExpressionRoot' - maybe not public or not valid?"}
GitLab Duo proposed an alternative, which failed on using this
in the annotation.
@PreAuthorize("@securityHelper.hasAnyListedAuthority(authentication, T(.springframework.security.access.expression.method.MethodSecurityExpressionRoot).this.returnObject.getClass().getMethod(T(.springframework.security.access.expression.method.MethodSecurityExpressionRoot).this.filterObject).getAnnotation(T(com.barclays.spone.loans.security.annotation.RequiresAnyRole)).value())")
Is there a way to retrieve the annotation parameters and pass them to SpEL expression?
For the record:
public boolean hasAnyListedAuthority(Authentication auth, String[] authorities) {
Set<String> userAuthorities = AuthorityUtils.authorityListToSet(auth.getAuthorities());
return Arrays.stream(authorities)
.anyMatch(userAuthorities::contains);
}