Using Spring interceptors

Spring interceptors can be used to process any request before it reaches the controller. These could be used, for example, to implement security features (authentication and authorization). Like request mappers, interceptors can also be declared for specific URL patterns. Let's add the login page to our application, which should be displayed before any other page in the application if the user has not already logged in.

We will first create UserDTO in the packt.jee.course_management.dto package. This class contains the username, password, and any message to be displayed on the login page, for example, authentication errors:

public class UserDTO { 
  private String userName; 
  private String password; 
  private String message; 
 
  public boolean messageExists() { 
    return message != null && message.trim().length() > 0; 
  } 
 
  //skipped setters and getters follow 
} 

Now, let's create the UserController that will process the login request. Once the user is logged in successfully, we would like to keep this information in the session.  The presence of this object in the session can be used to check whether the user is already logged in. Create the UserController class in the packt.jee.course_management.controller package:

@Controller 
public class UserController { 
} 

Add a handler method for the GET request for the login page:

  @RequestMapping (value="/login", method=RequestMethod.GET) 
  public String login (Model model) {
    UserDTO  user = new UserDTO(); 
    model.addAttribute("user", user); 
    return "login"; 
  } 

Note that we have specified the method attribute in the @RequestMapping annotation. When the request URL is /login and the HTTP request type is GET, only then will the login method be called. This method would not be called if a POST request is sent from the client. In the login method, we create an instance of UserDTO and add it to the Model so that it is accessible to the View.

We will add a method to handle POST requests from the login page. We will keep the same URL, that is, /login:

  @RequestMapping (value="/login", method=RequestMethod.POST) 
  public String doLogin (@ModelAttribute ("user") UserDTO user, 
  Model model) { 
 
    //Hard-coded validation of user name and 
//password to keep this example simple 
    //But validation could be done against database or 
//any other means here. 
    if (user.getUserName().equals("admin") && 
         user.getPassword().equals("admin")) 
      return "redirect:courses"; 
 
    user.setMessage("Invalid user name or password. Please try 
again"); return "login"; }

We now have two methods in UserController handling the request URL /login. However, the login method handles GET requests and doLogin handles POST requests. If authentication is successful in the doLogin method, then we redirect to the courses (list) page. Else, we set the error message and return to the login page.

Let's save the user object created in the login method in the HTTP session. This can be done with the simple @SessionAttributes annotation. You can specify the list of attributes in Model that need to be saved in the session too. Furthermore, we want to save the user attribute of Model in the session. Therefore, we will add the following annotation to the UserController class:

@Controller 
@SessionAttributes("user") 
 
public class UserController { 
} 

Now, let's create the login page. Create login.jsp in the views folder and add the following code in the HTML <body>:

<c:if test="${user.messageExists()}"> 
  <span style="color:red;"> 
    ${user.message}<br> 
  </span> 
</c:if> 
 
<form id="loginForm" method="POST"> 
  User Id : <input type="text" name="userName" required="required" 
value="${user.userName}"><br> Password : <input type="password" name="password"><br> <button type="submit">Submit</button> </form>

The page expects user (instance of UserDTO) to be available. It is made available by UserController through Model.

We now have the login page and UserController to handle the authentication, but how do we make sure this page is displayed for every request when the user is not logged in? This is where we can use Spring interceptors. We will configure an interceptor in the Spring context configuration file: servlet-context.xml. Add the following code to servlet-context.xml:

<interceptors> 
  <interceptor> 
    <mapping path="/**"/> 
      <beans:bean 
class="packt.jee.course_management.interceptor.LoginInterceptor"/> </interceptor> </interceptors>

In this configuration, we are telling Spring to call LoginInterceptor before executing any request (indicated by mapping path = "/**").

Let's now implement LoginInterceptor. Interceptors must implement HandlerInterceptor. We will make LoginInterceptor extend HandlerInterceptorAdapter, which implements HandlerInterceptor.

Create LoginInterceptor in the packt.jee.course_management.interceptor package:

@Component 
public class LoginInterceptor extends HandlerInterceptorAdapter { 
 
  public boolean preHandle(HttpServletRequest request, 
HttpServletResponse response, Object handler) throws Exception { //get session from request HttpSession session = request.getSession(); UserDTO user = (UserDTO) session.getAttribute("user"); //Check if the current request is for /login. In that case //do nothing, else we will execute the request in loop //Intercept only if request is not /login String context = request.getContextPath(); if (!request.getRequestURI().equals(context + "/login") && (user == null || user.getUserName() == null)) { //User is not logged in. Redirect to /login response.sendRedirect(request.getContextPath() + "/login"); //do not process this request further return false; } return true; } }

The preHandle method of the interceptor is called before Spring executes any request. If we return true from the method, then the request is handled further; else, it is aborted. In preHandle, we first check whether the user object is present in the session. The presence of the user object means that the user is already logged in. In such a case, we don't do anything more in this interceptor and return true. If the user is not logged in, then we redirect to the login page and return false so that Spring does not process this request further. 

Browse to http://localhost:8080/course_management/courses to test the login page. If you are not already logged in, the login page should be displayed.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.136.22.179