How to create a Spring Interceptor for Spring RESTful web services

92,349

Solution 1

Following steps can be taken to implement the interceptor with Spring:

  • Implement an interceptor class extending HandlerInterceptorAdapter class. Following is how the code could look like:

    public class LoginInterceptor extends HandlerInterceptorAdapter {
    
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception exception)
        throws Exception {
        // TODO Auto-generated method stub
    
        }
    
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
        throws Exception {
        // TODO Auto-generated method stub
    
        }
    
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    
            HandlerMethod handlerMethod = (HandlerMethod) handler;
    
            String emailAddress = request.getParameter("emailaddress");
            String password = request.getParameter("password");
    
            if(StringUtils.isEmpty(emailAddress) || StringUtils.containsWhitespace(emailAddress) ||
            StringUtils.isEmpty(password) || StringUtils.containsWhitespace(password)) {
                throw new Exception("Invalid User Id or Password. Please try again.");
            }
    
            return true;
        }
    
    
    }
    
  • Implement an AppConfig class or add the addInterceptors in one of the existing Configuration class. Note the path pattern specified with the LoginInterceptor instance

    @Configuration  
    public class AppConfig extends WebMvcConfigurerAdapter  {  
    
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
           registry.addInterceptor(new LoginInterceptor()).addPathPatterns("/account/login");
        }
    } 
    
  • Implement the controller method such as following:

    @Controller
    @RequestMapping("/account/login")
    public class LoginController {
    
        @RequestMapping(method = RequestMethod.GET)
        public String login() {
            return "login";
        }
    }
    

Solution 2

here an example of Interceptor :

public class AuthenticationInterceptor implements HandlerInterceptor  {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
        throws Exception {
         HandlerMethod handlerMethod = (HandlerMethod) handler;
        LoginRequired loginRequired = handlerMethod.getMethod().getAnnotation(LoginRequired.class);
        if (loginRequired == null) {
            return true;
        }

        String token = httpServletRequest.getParameter("token");

        if (StringUtils.isBlank(token)) {
            throw new MissingParameterException();
        }

        authenticationService.checkToken(token);

        return super.preHandle(httpServletRequest, httpServletResponse, handler);
    }
    @Override
    public void postHandle( HttpServletRequest request, HttpServletResponse response,
            Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("---method executed---");
    }
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
            Object handler, Exception ex) throws Exception {
        System.out.println("---Request Completed---");
    }

We can create an annotation :

 @Target({ElementType.METHOD, ElementType.TYPE})
        @Retention(RetentionPolicy.RUNTIME)
        public @interface LoginRequired {
        }

And then on controller, we had this annotation :

@RequestMapping(value = "/protected/controller")
@LoginRequired
public ResponseEntity<BaseResponse> controller() {
   ...
}

This is just a template/example to give you an idea. I hope this will help you.

Solution 3

There is a default solution for such things. spring security. And you will just have to implement something like:

@Configuration
@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsService userDetailsService;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .formLogin()
                .loginPage("/login")
                .failureUrl("/login?error")
                .usernameParameter("email")
                .permitAll()
                .and()
                .logout()
                .logoutUrl("/logout")
                .logoutSuccessUrl("/")
                .permitAll();
    }

    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth
                .userDetailsService(userDetailsService)
                .passwordEncoder(new BCryptPasswordEncoder());
    }
}

the dependency for it is:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

Solution 4

You should add this to regsiter your interceptor

@Configuration
public class MyConfiguration extends WebMvcConfigurerAdapter {

    @Bean
    AuthenticationInterceptor getAuthenticationInterceptor() {
        return new AuthenticationInterceptor();
    }

    @Override
    public void addInterceptors (InterceptorRegistry registry) {
        registry.addInterceptor(getAuthenticationInterceptor());

    }
}

Solution 5

After Spring 5 : Implementation should be like this: We should have a class that implements

HandlerInterceptor 

    public class CustomInterceptor implements HandlerInterceptorr{
}

Then we can register this interceptor by a class that implements WebMvcConfigurer and override the method addInterceptors

public class ServiceInterceptorAppConfig implements WebMvcConfigurer {
  @Autowired
  CustomInterceptor customInterceptor;

  @Override
  public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(customInterceptor);
  }
}
Share:
92,349

Related videos on Youtube

Praneeth Reddy
Author by

Praneeth Reddy

Updated on March 26, 2022

Comments

  • Praneeth Reddy
    Praneeth Reddy about 2 years

    I have some Spring RESTful (RestControllers) web services with no web.xml and I am using Spring boot to start the services.

    I want to add authorization layer for the web services and wanted to route all the http requests to one front controller before actually calling the web service itself. (I have a code to simulate sessions behavior at the autherisation layer, to validate a user based on a generated key that I send with each of the httpRequest from the client).

    Is there any Standard Spring solution on routing all the requests to a filter /front controller?

    Thanks in advance, Praneeth

    Edit: Adding my code

    Controller: `

    @RestController
    public class UserService {
        UserDAO userDAO = new UserDAO();
    
        @RequestMapping(value="/login", method = RequestMethod.POST)
        @LoginRequired
        public String login(@RequestParam(value="user_name") String userName, @RequestParam(value="password") String password, HttpServletRequest request){
            return userDAO.login(userName, password);
        }
    }`
    

    Interceptor:

    `

    public class AuthenticationInterceptor implements HandlerInterceptor  {
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
            System.out.println("In Interceptor");
            //return super.preHandle(request, response, handler);
            return true;
        }
        @Override
        public void postHandle( HttpServletRequest request, HttpServletResponse response,
                Object handler, ModelAndView modelAndView) throws Exception {
            System.out.println("---method executed---");
        }
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
                Object handler, Exception ex) throws Exception {
            System.out.println("---Request Completed---");
        }
    }
    

    `

    Interface. `

    @Target({ElementType.METHOD, ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface LoginRequired {
    }
    

    `

    • Sumesh TG
      Sumesh TG almost 6 years
      Set tocken or ID in request header and validate it.
  • Praneeth Reddy
    Praneeth Reddy almost 8 years
    Hello Pracede, Thanks for the reply. But this does'nt seem to be working. Should'nt we some where specify that Interceptor is being used(like any annotation or in any xml file). I've implemented the above logic but is not working. I've attached my code in the edit space of the question. I would be greatly thankful to you if you could help me in this
  • Ashutosh Shukla
    Ashutosh Shukla almost 7 years
    @Component public class LoginInterceptor extends HandlerInterceptorAdapter{ ............} i.e Adding Component annotation over LoginInterceptor helped me
  • lrxw
    lrxw about 6 years
    How do you know you get a HandlerMethod passed to your LoginInterceptor?
  • T3rm1
    T3rm1 over 5 years
    @PraneethReddy You need to override addInterceptors method in WebMvcConfigurer. Also annotate your class with @Configuration
  • Double M
    Double M over 5 years
    WebMvcConfigurerAdapter is now deprecated. Implement WebMvcConfigurer instead.
  • Ram Thota
    Ram Thota over 3 years
    It helped me a lot. Thank you.
  • JasonBodnar
    JasonBodnar almost 3 years
    What's the point of the annotation if you have add the interceptor?