In some scenarios, we need to get HandlerMethod
ahead of org.springframework.web.reactive.DispatcherHandler, such as an implement of authentication by WebFilter
public class AuthFilter implements WebFilter, Ordered {
@Autowired
private RequestMappingHandlerMapping handlerMapping;
@Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
return handlerMapping.getHandler(exchange).switchIfEmpty(chain.filter(exchange))
.flatMap(handler -> {
if (handler instanceof HandlerMethod) {
HandlerMethod methodHandle = (HandlerMethod) handler;
CheckPermission permission = methodHandle.getMethodAnnotation(CheckPermission.class);
if (Objects.isNull(permission)) {
permission = AnnotationUtils.findAnnotation(methodHandle.getBeanType(), CheckPermission.class);
}
if (Objects.nonNull(permission)) {
// TODO do something..
}
}
return chain.filter(exchange);
}
);
}
}
HandlerMethod
is necessary but there is no alternative way to get it withon WebFilter, which limited the capabilities of WebFilter. so, we need call getHandler
, however this may lead to repeated call of lookupHandlerMethod as issue:
https://github.com/spring-projects/spring-framework/blob/00da70e26b9cb5ece2a9499e7c1b449e856b4aea/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/AbstractHandlerMethodMapping.java#L293
To avoid duplicate search for HandlerMethod
in mapping.getHandler
, I suggest implementing a improved getHandlerInternal, in which HandlerMethod
would be searched in attributes at first.
Object handlerMethod = exchange.getAttributes().get(BEST_MATCHING_HANDLER_ATTRIBUTE);
if (handlerMethod instanceof HandlerMethod) {
return Mono.just((HandlerMethod) handlerMethod);
}
related issue:https://github.com/spring-projects/spring-framework/issues/29591
Comment From: rstoyanchev
WebFilter
s are called first and are not meant to know what the DispatcherHandler
will do or what controller method it will choose. You can of course call a HandlerMapping
from a WebFilter
, but that is not something that we recommend or support.