- Creating the Interceptor
To implement an interceptor, create a class that implements the HandlerInterceptor interface. This interface defines three callback methods: preHandle, postHandle, and afterCompletion. For authentication purposes, the preHandle method is the primary focus, as it executes before the target controller method is invoked.
Inside preHandle, the logic typically involves checking if the request targets the login page itself (which should always be accessible) and verifying the existence of a valid session attribute.
package com.example.web.interceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.springframework.web.servlet.HandlerInterceptor;
public class AuthenticationInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String requestPath = request.getRequestURI();
// Allow access to the login page and authentication endpoint without interception
if (requestPath.contains("/login")) {
return true;
}
// Check for existing user session
HttpSession session = request.getSession();
String user = (String) session.getAttribute("currentUser");
if (user != null) {
// User is authenticated, proceed to the controller
return true;
} else {
// User is not authenticated, redirect to login view
request.getRequestDispatcher("/WEB-INF/views/login.jsp").forward(request, response);
return false;
}
}
}
- Configuring the Interceptor
Once the interceptor class is defined, it must be registered in the Spring MVC configuration file (spring-mvc.xml). The <mvc:interceptors> tag allows you to define one or more interceptors and specify the URL patterns they apply to.
<mvc:interceptors>
<mvc:interceptor>
<!-- Apply to all paths -->
<mvc:mapping path="/**"/>
<!-- Exclude static resources if necessary -->
<bean class="com.example.web.interceptor.AuthenticationInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
- The Login View
A simple JSP page is required to capture user credentials. This form submits a POST request to the authentication endpoint.
<html>
<head>
<meta charset="UTF-8">
<title>System Login</title>
</head>
<body>
<form action="./auth/verify" method="post">
Username: <input type="text" name="username" required/><br/>
Password: <input type="password" name="password" required/><br/>
<input type="submit" value="Login"/>
</form>
</body>
</html>
- Login Controller and Handling POST Requests
The controller handles the incoming login request. If the credentials are valid, a session attribute is set, and the user is redirected to the main page.
package com.example.web.controller;
import javax.servlet.http.HttpSession;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
@Controller
@RequestMapping("/auth")
public class AuthController {
@PostMapping("/verify")
public String verifyCredentials(@RequestParam("username") String username,
@RequestParam("password") String password,
HttpSession session) {
// Simplified credential check
if ("admin".equals(username) && "secret".equals(password)) {
session.setAttribute("currentUser", username);
// Redirect after successful login
return "redirect:/dashboard/home";
}
// Return to login on failure
return "redirect:/login";
}
}
- Handling the "405 Method Not Allowed" Error
A common pitfall occurs when using forward versus redirect after a successful login. If the controller logic attempts to forward a POST request to a method mapped to a GET request, the server will return an HTTP 405 error.
Forward vs. Redirect
- Forward: A server-side operation where the request is passed internally to another resource. The original HTTP method (e.g., POST) is preserved. If the target resource does not support POST, an error occurs.
- Redirect: A client-side operation where the server sends a 3xx status code (usually 302) instructing the browser to make a new GET request to a different URL. This resets the request method to GET.
In the login scenario, after processing a POST request, it is best practice to use redirect: to navigate to the landing page. This ensures a new GET request is initiated, avoiding method mismatch issues and preventing form resubmission on browser refresh.
- Alternative: WebRequestInterceptor
Spring MVC also offers the WebRequestInterceptor interface. Unlike HandlerInterceptor, which uses HttpServletRequest, this interface operates on a WebRequest object. It is useful when you want to intercept requests but do not need direct access to the underlying Servlet API components like HttpServletResponse. The configuration and lifecycle methods (preHandle, postHandle, afterCompletion) remain conceptually similar.