Description
Expected Behavior
PrePostAdviceReactiveMethodInterceptor
should enable the user to customize how the supported methods are detected.
Current Behavior
The current logic checks whether the intercepted method returns a Publisher
and, as of a couple of days ago, whether it is a Kotlin suspending function or returns Kotlin's Flow
. It enables no customization by the user.
Context
Enabling a degree of extensibility to this logic could make Spring Security usable in more scenarios.
More supported kinds of methods could be added by framework/language/library authors as a part of their own Spring integration. Examples might include libraries (like Mutiny, which doesn't comply with the reactive streams spec), or languages (e.g. Scala or Groovy specific types, akin to Kotlin's Flow
). An even more interesting example are workflow orchestration/BPMN engines, that invoke configured methods (usually reflectively) and commonly have their own interceptors and a shared context available around every invocation. This context can act as an alternative side-channel by which the Reactor context can be propagated even when the reactive chain is interrupted. This means that in such environments any method could potentially be wrapped in e.g. Mono
with the Reactor context fully preserved. This exact scenario is the one I'm facing. I'm developing a Spring Boot starter around graphql-java, which (like all GraphQL environments) provides a shared context available around each method invocation. This enables me to store Reactor's context inside the GraphQL context, wrap any method invocation into a Mono
and re-attach the Reactor context. So despite graphql-java having no support for reactive streams and working only with CompletableFutures
, Spring's reactive security keeps working just fine as the chain of reactive calls remains effectively unbroken. I have a limited yet fully working implementation, but it requires the underlying method to return a Publisher
for no other reason than to satisfy the checks in PrePostAdviceReactiveMethodInterceptor
. If these could be extended somehow, any method would be supported. My current implementation provides no way for the wrapped methods to enrich/replace the Reactor context, but that is entirely possible too, with all the semantics properly preserved (like only downstream methods having the new context etc).
Additionally, Spring Security could itself use this extensibility to cleanly register more supported method types as they get added in the future. The current list consisting of Publisher
-returning and Kotlin-specific methods is unlikely to stay fixed forever, and PrePostAdviceReactiveMethodInterceptor
is already complicated enough with a few nested if
s containing entirely divergent logic. E.g. Flow
-handling logic shares virtually nothing with the Mono
-handling one.
Possible approaches
PrePostAdviceReactiveMethodInterceptor
could delegate the check if the method is supported to an injectable strategy, that would also be an adapter to/from Publisher
(like how Flow
is currently adapted). Perhaps hooking into ReactiveAdapterRegistry
more formally is the way to go...
Alternatively, maybe a special subtype of MethodInvocation
, e.g. ReactiveAdaptedInvocation
that itself acts as the strategy/adapter could be used.
I'd happily undertake this work if there is interest, but I'd really need some discussion on the approach first.