I am a Spring Security novice. If the question description is unprofessional and inaccurate, please help me improve it.
I want to intervene in the method security evaluation process of Spring Security 6
and insert a piece of code:
If the current logged-in user has "SYSTEM" permissions, skip the method security evaluation (including @PreAuthorize, @Secured, jsr250 annotations, and any SpEL).
I tried to customize PermissionEvaluator
. I provide a DefaultMethodSecurityExpressionHandler
Bean with setPermissionEvaluator(myCustomPermissionEvaluator)
. It only takes effect in the case of @PreAuthorize("hasPermission")
, and other SpEL expressions or @PreAuthorize("isAuthenticated()")
, will not take effect.
After some debugging, I found that the invoke
method or attemptAuthorization
method of AuthorizationManagerBeforeMethodInterceptor
is my ideal insertion place, but this class is final
:
/**
* A {@link MethodInterceptor} which uses a {@link AuthorizationManager} to determine if
* an {@link Authentication} may invoke the given {@link MethodInvocation}
*
* @author Evgeniy Cheban
* @author Josh Cummings
* @since 5.6
*/
public final class AuthorizationManagerBeforeMethodInterceptor implements AuthorizationAdvisor {
// ...
/**
* Determine if an {@link Authentication} has access to the {@link MethodInvocation}
* using the configured {@link AuthorizationManager}.
* @param mi the {@link MethodInvocation} to check
* @throws AccessDeniedException if access is not granted
*/
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
return attemptAuthorization(mi);
}
// ...
private Object attemptAuthorization(MethodInvocation mi) throws Throwable {
this.logger.debug(LogMessage.of(() -> "Authorizing method invocation " + mi));
AuthorizationResult result;
try {
result = this.authorizationManager.authorize(this::getAuthentication, mi);
}
catch (AuthorizationDeniedException denied) {
return handle(mi, denied);
}
this.eventPublisher.publishAuthorizationEvent(this::getAuthentication, mi, result);
if (result != null && !result.isGranted()) {
this.logger.debug(LogMessage.of(() -> "Failed to authorize " + mi + " with authorization manager "
+ this.authorizationManager + " and result " + result));
return handle(mi, result);
}
this.logger.debug(LogMessage.of(() -> "Authorized method invocation " + mi));
return proceed(mi);
}
// ...
}
My understanding (not necessarily correct) is that in the entire method call chain of the framework, the this.authorizationManager.authorize
of the attemptAuthorization
method enters the implementation of various (PreAuthorize, Secured, Jsr250) AuthorizationManagers, so I must insert my code before this. The front of the AuthorizationManagerBeforeMethodInterceptor
seems to be the AOP aspect, and there is no opportunity for me to intervene.
Is there any feasible way for me to do this?
Any suggestions are welcome and grateful.