How to create a Spring Interceptor for Spring RESTful web services
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 {
}
`
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());
}
}