I define an interceptor in spring-boot.
I override the preHandle method.
the interceptor is invoking for all HTTP commands : GET/PUT/POST/PATCH/DELETE/HEAD/OPTIONS
but it doesn't invoked for TRACE command.
what am I miss?
the interceptor:
#Component
public class BlockingHttpInterceptor implements HandlerInterceptor {
private final Class<?> thisClass = this.getClass();
private String BASE_URL = "/subscribers";
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if (HttpMethod.GET.matches(request.getMethod())
|| HttpMethod.POST.matches(request.getMethod())
|| (HttpMethod.DELETE.matches(request.getMethod()) && request.getRequestURI().startsWith(BASE_URL))
|| HttpMethod.PATCH.matches(request.getMethod())) {
return true;
} else {
response.sendError(HttpStatus.METHOD_NOT_ALLOWED.value());
return false;
}
}
}
the interceptor config:
#Configuration
public class InterceptorConfig implements WebMvcConfigurer {
#Autowired
private BlockingHttpInterceptor blockingHttpInterceptor;
#Override
public void addInterceptors(InterceptorRegistry registry){
registry.addInterceptor(blockingHttpInterceptor).addPathPatterns("/**");
}
}
As explained in the JavaDoc for the DispatcherServlet the TRACE request are by default not dispatched, hence they will never reach your controllers/interceptor.
Luckily you are using Spring Boot which makes configuring this quite easy through the spring.mvc.dispatch-trace-request property, which is by default false. Setting this to true in your application.properties will enable dispatching for TRACE request.
spring.mvc.dispatch-trace-request=true
Adding the above to your properties will enable it and will make things work as you expect.
Related
I migrate the code to springboot and our API works well. Only interceptor can't be triggerred.
I googled related solutions and modify the code to right format which still failed to trigger the interceptor.
In our project, we also have the filter which extends OncePerRequestFilter and works.
It makes me confused.
They should be no big difference.
Btw, AOP is used in the project.
It's my code.
JerseyConfig.class
#Configuration
public class JerseyConfig extends ResourceConfig {
public JerseyConfig(){
packages("com.xxx");
}
}
VaultAuthorizationInterceptor.class
#Component
public class VaultAuthorizationInterceptor implements HandlerInterceptor {
private static final Logger logger = LoggerFactory.getLogger(VaultAuthorizationInterceptor.class);
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
logger.info("test");
return true;
}
}
VaultAuthConfig.class
#Configuration
public class VaultAuthConfig implements WebMvcConfigurer {
#Bean
public VaultAuthorizationInterceptor getVaultInterceptor() {
return new VaultAuthorizationInterceptor();
}
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(getVaultInterceptor()).addPathPatterns("/**");
}
}
When you are using the spring-boot-starter-jersey, you use jersey as your web stack. That means any requests will processed by jersey. So you have to register a jersey filter or interceptor. Take a look at the jersey documantation. There is described how to use filters and interceptors. I think you want to use a filter because interceptors in the jersey stack used to manipulate the input or output stream.
Is there any annotation similar to #PreAuthorize or #PreFilter that I can use to run code before a method in the Controller is invoked?
I need to add info to the request context (specific to the method being called) to be then retrieved by the ExceptionHandler.
For example
#RestController
public MyController{
#UnkwonwAnnotation("prepareContext(request.getAgentId())"){
public ResponseEntity method1(RequestA requestA) {
...
}
#UnkwonwAnnotation("prepareContext(request.getUserName())"){
public ResponseEntity method1(RequestB requestB) {
...
}
}
I could actually just use #PreAuthorize but doesn't feel right
You Can add interceptor for this
Sample Interceptor
public class CustomInterceptor implements HandlerInterceptor {
#Override
public boolean preHandle(HttpServletRequest request,HttpServletResponse response) {
//Add Login here
return true;
}
}
Configuration
#Configuration
public class MyConfig extends WebMvcConfigurerAdapter {
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyCustomInterceptor()).addPathPatterns("/**");
}
}
Hope this helps
Spring Aspect is also a good option to execute code before controller.
#Component
#Aspect
public class TestAspect {
#Before("execution(* com.test.myMethod(..)))")
public void doSomethingBefore(JoinPoint jp) throws Exception {
//code
}
}
Here myMethod() will execute before controller.
Maybe a good option is implement a custom filter that runs every time that a request is received.
You need extend "OncePerRequestFilter" and overwrite the method "doFilterInternal"
public class CustomFilter extends OncePerRequestFilter {
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
//Add attributes to request
request.getSession().setAttribute("attrName", new String("myValue"));
// Run the method requested by petition
filterChain.doFilter(request, response);
//Do something after method runs if you need.
}
}
After you have to register the filter in Spring with FilterRegistrationBean. If you have Spring security yo need add your filter after security filter.
Expanding on Sai Prateek answer, I'v created a custom annotation:
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
public #interface OperationContext {
String clientId();
String userId();
String operation();
}
and a component to handle it:
#Aspect
#Component
public class OperationContextAspect {
#Before(value = "#annotation(operationContext)", argNames = "operationContext")
public void preHandle(OperationContext operationContext) {
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
requestAttributes.setAttribute("operation", operationContext.operation, RequestAttributes.SCOPE_REQUEST);
requestAttributes.setAttribute("clientId", operationContext.clientId(), RequestAttributes.SCOPE_REQUEST);
requestAttributes.setAttribute("userId", operationContext.userId(), RequestAttributes.SCOPE_REQUEST);
}
}
I then annotate the controller methods providing the required parameters:
#RestController
public class MyController {
#OperationContext(clientId = '#request.getClientId', userId = '#request.getUserId', operation = "OPERATION_A")
public ResponseEntity aMethod(MyRequest request) {
...
}
}
I am midway through upgrading from Spring Boot 1.x to Spring Boot 2.0 and have noticed I have started getting class cast errors in my HandlerInterceptors.
For example, in one HandlerInterceptor I look if the controller method/endpoint is annotated with #AdminOnly to restrict access to certain endpoints.
#Component
public class AdminOnlyInterceptor implements HandlerInterceptor {
#Override
public boolean preHandle(HttpServletRequest httpRequest, HttpServletResponse httpResponse, Object handler) {
HandlerMethod hm = (HandlerMethod) handler;
Method method = hm.getMethod();
if (method.getDeclaringClass().isAnnotationPresent(RestController.class) && (method.isAnnotationPresent(AdminOnly.class) || method.getDeclaringClass().isAnnotationPresent(AdminOnly.class))) {
// Some Logic returning true or false
}
return true;
}
}
This worked in Spring Boot 1.5.x.
After upgrading I now get the following exception:
java.lang.ClassCastException: org.springframework.web.servlet.resource.ResourceHttpRequestHandler cannot be cast to org.springframework.web.method.HandlerMethod
I couldn't find anything relevant in the migration guide. How can I upgrade but keep the interceptor above working?
It appears Spring Boot 2.x Interceptors now also process Static Resource requests, so these now need to be manually excluded when registering the interceptor like below:
#Configuration
public class ControllerConfiguration implements WebMvcConfigurer {
private final AdminOnlyInterceptor adminInterceptor;
#Autowired
public ControllerConfiguration(AdminInterceptor adminInterceptor) {
this.adminInterceptor = adminInterceptor;
}
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(adminInterceptor)
.addPathPatterns("/rest-api-root/**"); // White list paths
//.excludePathPatterns("/static-resource-root/**"); // Black list paths
}
}
Source
http://docs.spring.io/spring/docs/current/spring-framework-reference/html/mvc.html#mvc-handlermapping
I have Controller classes annotated with #Controller, they have methods annotated with #RequestMapping. My task is to audit all the web requests received by the Controller classes to #RequestMapping methods, I am using datatables on UI to send and receive response from controllers. the Audit framework is already in place.
The project is configured in Java Config.
I am not sure how to proceed on getting this done.
// Configure Interceptor
public class WebConfig extends WebMvcConfigurerAdapter {
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyInterceptor());
}
public #Bean
RequestMappingHandlerMapping requestMappingHandlerMapping() {
RequestMappingHandlerMapping handlerMapping = new RequestMappingHandlerMapping();
handlerMapping.setAlwaysUseFullPath(true);
handlerMapping.setUseSuffixPatternMatch(false);
return handlerMapping;
}
}
//Add Handler
#Component
public class MyInterceptor extends HandlerInterceptorAdapter {
#Inject RequestMappingHandlerMapping requestMappingHandlerMapping;
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
// do stuff - ( Does my Audit Code go here? eg: Logger.info("xyz request"))
return true;
}
}
I was thinking something like this would work.
Any Suggestions on this, and
if its easier Using Listener or some other Interceptor, it would be helpful
Using interceptors you have full access to the HandlerMethod which provides convenient access to method parameters, the method return value, method annotations, etc.
The following example intercepts and logs mapped requests.
class WebMvcConfig extends WebMvcConfigurerAdapter {
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new HandlerInterceptorAdapter() {
Logger logger = LoggerFactory.getLogger(WebMvcConfig.class);
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if (handler instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
Method method = handlerMethod.getMethod();
logger.info("{} - {} - method '{}' on controller '{}'",
request.getMethod(), request.getRequestURI(), method.getName(),
handlerMethod.getBean().getClass()
);
}
return true;
}
});
}
}
It returns true to continue with the execution chain (and forward the request to other interceptors or the controller-method itself).
An example log-output looks like:
GET - /greeting - method 'greeting' on controller 'class hello.GreetingController'
I am trying to intercept every HTTP request that comes into my Spring Boot application.
For this I have a LoggingInterceptor as follows:
#Component
public class LoggingInterceptor extends HandlerInterceptorAdapter {
private static final Logger logger = LoggerFactory.getLogger(LoggingInterceptor.class);
public LoggingInterceptor() {
super();
logger.debug("LoggingInteceptor constructor");
}
#Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
logger.debug("LoggingInteceptor: Intercepted " + request.getRequestURI());
return true;
}
}
Then, I have an #Configuration class for adding the interceptor to the registry as follows:
#EnableWebMvc
#Configuration
public class LoggingConfig extends WebMvcConfigurerAdapter {
#Autowired
LoggingInterceptor loggingInterceptor;
public void addInterceptors(InterceptorRegistry registry){
registry.addInterceptor(loggingInterceptor);
}
}
However, I just cannot see any of the logger statements. Is there something more I need to do to get this going?
Your configuration looks fine. Also registry.addInterceptor(loggingInterceptor); call would fail if interceptor would be null, therefore it seems to be correctly wired.
Therefore I would verify:
if DEBUG level us enabled in logging framework
If both classes are included into your Spring context at all (put breakpoint addInterceptors method and start app)
EDIT:
OK, so comment confirmed that you your problem is my first point.
You need to find out logging configuration file (e.g. log4j.properties, log4j,xml or logback.xml) and change log level from INFO to DEBUG there.