Let's say we have two interceptors "LogInterceptor" and "AuthInterceptor".
The first interceptor logs the incoming request and the second one authenticate it.
Aim: Chain LogIntercptor and AuthInterceptor. First I want the logInterceptor be called and after that AuthInterceptor should be executed.
Note: I know about "redirect" and returning false (Please don't suggest the one)
---------------------Log Interceptor---------------------------------------
//First Inteceptor
#Component
public class LogInterceptor extends HandlerInterceptorAdapter
{
private final Logger Logger =
LoggerFactory.getLogger(this.getClass());
#Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
//take action base on incoming IP
long startTime = System.currentTimeMillis();
request.setAttribute("startTime",startTime);
if(request.getRemoteAddr().startsWith("192"))
{
response.sendRedirect("/auth-failed"); //redirect to default
return false;
}
return true;
}
#Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response, Object handler, #Nullable ModelAndView
modelAndView) throws Exception
{
}
#Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response, Object handler, #Nullable Exception
ex) throws Exception
{
}
}
//Second interceptor "Code is however not complete, I am just seeeking how this can be achieved."
class AuthInterceptor
{
}
You just need to make sure the Interceptor are added in your desired orders when configuring InterceptorRegistry:
#EnableWebMvc
#Configuration
public class WebConfig implements WebMvcConfigurer{
#Autowired
private LogInterceptor logInterceptor;
#Autowired
private AuthInterceptor authInterceptor;
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(logInterceptor);
registry.addInterceptor(authInterceptor);
}
}
In case you have multiple WebMvcConfigurer , you can simply use #Order to control which the execution order of WebMvcConfigurer (lower value has higher priority):
#EnableWebMvc
#Configuration
#Order(1)
public class FooWebConfig implements WebMvcConfigurer{
}
#EnableWebMvc
#Configuration
#Order(2)
public class BarWebConfig implements WebMvcConfigurer{
}
Related
I have a problem with my RestController interceptor.
My goal is to get the RestController path in a HandlerInterceptorAdapter and then use it to create metrics.
Via the interface HttpServletRequest I have access to the path, but it is resolved there.
Example of what I would like to get in my interceptor:
GET: object/123 // wrong
GET object/{id} // right
Is there any way to get the path without resolved variables?
Here is my implementation:
RestController:
#RestController
public class ObjectController
{
#GetMapping("object/{id}")
public String getObjectById(#PathVariable String id)
{
return id;
}
}
Config:
#Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter
{
#Override
public void addInterceptors(InterceptorRegistry registry)
{
registry.addInterceptor(new RequestInterceptor());
}
}
Interceptor:
public class RequestInterceptor extends HandlerInterceptorAdapter
{
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception
{
System.out.println(request.getRequestURI());
return true;
}
#Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
#Nullable ModelAndView modelAndView) throws Exception
{
System.out.println(request.getRequestURI());
}
#Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
#Nullable Exception ex) throws Exception
{
System.out.println(request.getRequestURI());
}
}
I want my prehandle method to be called.On debugging i see the control going inside ProductServiceInterceptor class but none of the methods inside are getting called
#EnableWebMvc
#Configuration
public class ProductServiceInterceptorAppConfig extends WebMvcConfigurerAdapter {
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new productServiceInterceptor()).addPathPatterns("/home/*"));
}
}
#Component
public class ProductServiceInterceptor implements HandlerInterceptor {
#Override
public boolean preHandle(
HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
return true;
}
#Override
public void postHandle(
HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {}
#Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception exception) throws Exception {}
}
I am implementing an interceptor for logging purposes. I know once i called the getReader method on HttpServletRequest will loose the body data, but i was experimenting. So i ran the below code, and realized the controller is never invoked (Debug point is not activated) and there was no errors.
#Component
public class IncomingRequestInterceptor extends HandlerInterceptorAdapter {
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
String requestPayload = request.getReader().lines().collect(Collectors.joining(System.lineSeparator()));
System.out.println(requestPayload);
return super.preHandle(request, response, handler);
}
#Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
super.afterCompletion(request, response, handler, ex);
}
}
And the controller
#PostMapping("/test")
public String test(#Valid #RequestBody CredentialsVo credentials) {
credentials.getUsername();
.............
return "test";
}
Filter Registration
#Configuration
public class MyConfig implements WebMvcConfigurer {
#Autowired
IncomingRequestInterceptor incomingRequestInterceptor;
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(incomingRequestInterceptor)
.addPathPatterns("/**");
}
}
if i do not call getReader() method, the controller is invoked. I was actually expecting the controller is called but i would get a null pointer or something like that.
Could anyone tell me how spring acts in this scenario ?
I am trying to create an interceptor for the first time in my spring boot application, but somehow it is not created automatically, as described in the tutorials.
I've tried to create a WebConfig class that extends the WebMvcConfigurerAdapter class and annotated it as a #Component but it haven't worked. I also tried to create a WebConfig that implements the WebMvcConfigurer interface with #Configuration and #EnableWebMvc annotations but it hadn't worked either.
current WebConfig class:
#Configuration
#EnableWebMvc
#ComponentScan("com.*")
public class WebConfig implements WebMvcConfigurer {
public WebConfig() {
super();
}
#Autowired
HandlerInterceptor headerModifierInterceptor;
#Override
public void addInterceptors(InterceptorRegistry registry) {
System.out.println("------------------hi");
registry.addInterceptor(headerModifierInterceptor);
}
}
Application class
#SpringBootApplication
#EnableWebSecurity
#ComponentScan(basePackages = {"com.*"})
#EntityScan("com")
public class CoreRestAPIApplication {
public static void main(String[] args) {
SpringApplication.run(CoreRestAPIApplication.class, args);
}
}
My interceptor class:
#Component
public class RestTemplateHeaderModifierInterceptor
implements HandlerInterceptor {
#Autowired
AuthUtil authUtil;
#Autowired
JwtTokenProvider jwtTokenProvider;
#Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
String resolvedToken = jwtTokenProvider.resolveToken(request);
if (!StringUtils.isEmpty(resolvedToken)) {
String updatedToken = jwtTokenProvider.createToken(jwtTokenProvider.getUsername(resolvedToken), jwtTokenProvider.getAuthentication(resolvedToken).getAuthorities());
response.addHeader(authUtil.AUTH_HEADER_NAME, updatedToken);
}
}
}
After some search, I've found that I have a registered WebMvcConfigurationSupport configuration. However, if someone is looking and wishes to modify headers using an interceptor, DO NOT use an interceptor for that, as for spring will not handle it well if you return a ResponseEntity or your controller method returns a #ResponseBody.
Instead(at least for my use which is filtering and renewing a token every time a valid request is received) use the doFilterInternal method to add the header to the response(or add a cookie if you wish..) here is an example of how I did it:
public class JwtTokenFilter extends OncePerRequestFilter {
private JwtTokenProvider jwtTokenProvider;
public JwtTokenFilter(JwtTokenProvider jwtTokenProvider) {
this.jwtTokenProvider = jwtTokenProvider;
}
#Override
protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
String token = jwtTokenProvider.resolveToken(httpServletRequest);
try {
if (token != null && jwtTokenProvider.validateToken(token)) {
Authentication auth = jwtTokenProvider.getAuthentication(token);
SecurityContextHolder.getContext().setAuthentication(auth);
if(!jwtTokenProvider.isExpired(token)) {
httpServletResponse.setHeader("authKey", jwtTokenProvider.createToken(jwtTokenProvider.getUsername(token), auth.getAuthorities()));
}
}
} catch (ClientErrorException ex) {
//this is very important, since it guarantees the models is not authenticated at all
SecurityContextHolder.clearContext();
httpServletResponse.sendError(ex.getStatus().value(), ex.getMessage());
return;
}
filterChain.doFilter(httpServletRequest, httpServletResponse);
}
}
In my Spring Boot 2 project I use a simple interceptor that was working fine. However after creating a custom HandlerAdapter and SimpleUrlHandlerMapping the interceptor never executed again.
public class RequestMonitoringInterceptor extends HandlerInterceptorAdapter {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
logger.debug("preHandle");
return super.preHandle(request, response, handler);
}
...
}
And registered in my WebConfig as:
#Configuration
public class WebConfig implements WebMvcConfigurer {
#Bean
public RequestMonitoringInterceptor requestMonitoringInterceptor() {
return new RequestMonitoringInterceptor();
}
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(requestMonitoringInterceptor());
}
}
Any idea what I have missed?