How to do it...

This recipe will provide proof that Spring 5 can work with the current Spring Security 4.2.2 without encountering any conflicts:

  1. To integrate the Spring Security 4.2.2 framework, include the following Maven dependencies into the Maven repository:
<dependency> 
  <groupId>org.springframework.security</groupId> 
  <artifactId>spring-security-web</artifactId> 
  <version>4.2.2.BUILD-SNAPSHOT</version> 
</dependency> 
<dependency> 
  <groupId>org.springframework.security</groupId> 
  <artifactId>spring-security-config</artifactId> 
  <version>4.2.2.BUILD-SNAPSHOT</version> 
</dependency> 
<dependency> 
  <groupId>org.springframework.security</groupId> 
  <artifactId>spring-security-taglibs</artifactId> 
  <version>4.2.2.BUILD-SNAPSHOT</version> 
</dependency> 
  1. Reuse the SpringWebInitializer, SpringDispatcherConfig, SpringDbConfig, and SpringContextConfig. Set their @ComponentScan base packages to org.packt.secured.mvc. The following is the final directory structure with these three main @Configuration files:
Be sure to have an empty SpringContextConfig context definition.
  1. Now, create another context definition which will implement the security model consisting of the Spring Security 4.2.2 APIs. Let us start with the creation of AppSecurityConfig inside org.packt.secured.mvc.core, which lists all the basic security rules for our MVC application:
@Configuration 
@EnableWebSecurity 
public class AppSecurityConfig extends  
    WebSecurityConfigurerAdapter { 
   
    @Override 
    protected void configure(AuthenticationManagerBuilder auth) throws Exception { 
       auth.inMemoryAuthentication() 
          .withUser("sjctrags").password("sjctrags") 
          .roles("USER"); 
    } 
  
   @Override 
   protected void configure(HttpSecurity http) throws Exception { 
        http 
          .authorizeRequests() 
          .antMatchers("/login*").permitAll() 
          .anyRequest().authenticated() 
          .and() 
          .formLogin() 
          .loginPage("/login.html") 
          .defaultSuccessUrl("/deptform.html") 
          .failureUrl("/login.html?error=true") 
          .and().logout().logoutUrl("/logout.html") 
          .logoutSuccessUrl("/after_logout.html"); 
                    
         http.csrf().disable(); 
    } 
   
    @Override 
    public void configure(WebSecurity web) throws Exception  
    { 
      web 
        .ignoring() 
           .antMatchers("/resources/**") 
           .antMatchers("/css/**") 
           .antMatchers("/js/**") 
           .antMatchers("/image/**"); 
    } 
}

The difference between the Spring MVC context definition and the Spring Security one is the presence of @EnableWebSecurity in the latter. This annotation enables security in the application through the creation of a servlet named springSecurityFilterChain, which is responsible for all the core and extra security features. To complete the @Configuration, the class must extend org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter to override the needed security-related methods.

Do not use @EnableWebMVCSecurity anymore since it has been considered as deprecated by Spring Security 4.x.
  1. To apply AppSecurityConfig, import this context to our application context SpringContextConfig through the @Import annotation:
@Import(value = { AppSecurityConfig.class }) 
@Configuration 
@EnableWebMvc 
@ComponentScan(basePackages = "org.packt.secured.mvc") 
public class SpringContextConfig {  } 
This annotation is the same with the <import> tag used when augmenting two or more XML-based definitions.
  1. Then, create SpringSecurityInitializer inside the package org.packt.secured.mvc.core that will register the delegatingFilterproxy filter to be used by the springSecurityFilterChain previously created. So far, this strategy is the one working when compared to the direct Filter.Registration of the ServletContext:
public class SpringSecurityInitializer extends  
  AbstractSecurityWebApplicationInitializer { } 
Leave this class empty.
  1. At this point, it is time to implement our MVC application starting with the model objects. Reuse Department and Employee from the ch03-jdbc project. Drop these files inside org.packt.secured.mvc.model.data.
  2. Reuse also our form backing objects from ch03-jdbc, namely DepartmentForm and EmployeeForm. Place them inside the package org.packt.secured.mvc.model.data.form.
  3. For the DAO layer, let us consider implementing a new DepartmentDao, which contains the following method signatures:
public interface DepartmentDao { 
  public List<Department> getDepartments(); 
  public Department getDepartmentData(Integer id); 
  public void addDepartmentBySJI(Department dept); 
  public void addDepartmentByJT(Department dept); 
  public void updateDepartment(Department dept); 
  public void delDepartment(Integer deptId); 
} 
  1. Place this in the org.packt.secured.mvc.dao package.
  2. Implement DepartmentDaoImpl by using SimpleJdbcInsert and JdbcTemplate from ch03-jdbc, and place them in the org.packt.secured.mvc.dao.impl package. Be cautious with the use of SimpleJdbcInsert's addDepartmentBySJI(), which gives the HTTP status 500 during successive calls to the jdbcInsert.withTableName("department") line.
  3. Implement a new DepartmentController which contains create, delete, update record, and query database transactions after a successful login:
@Controller 
public class DepartmentController { 
   
  @Autowired 
  private DepartmentService departmentServiceImpl; 
   
  @RequestMapping("/deptform.html") 
  public String initForm(Model model){ 
 
    DepartmentForm departmentForm = new DepartmentForm(); 
    model.addAttribute("departmentForm", departmentForm); 
    return "dept_form";   
  } 
   
  @RequestMapping(value={"/deptform.html"},  
            method=RequestMethod.POST) 
  public String submitForm(Model model,  
    @ModelAttribute("departmentForm") DepartmentForm  
                departmentForm){ 
 
      departmentServiceImpl.addDepartment(departmentForm); 
      model.addAttribute("departments",  
        departmentServiceImpl.readDepartments()); 
      return "dept_result"; 
  } 
   
  @RequestMapping("/deldept.html/{deptId}") 
  public String deleteRecord(Model model,  
     @PathVariable("deptId") Integer deptId){ 
    departmentServiceImpl.removeDepartment(deptId); 
    model.addAttribute("departments",  
      departmentServiceImpl.readDepartments()); 
    return "dept_result"; 
  } 
   
  @RequestMapping("/updatedept.html/{id}") 
  public String updateRecord(Model model,  
    @PathVariable("id") Integer id){ 
 
    Department dept = departmentServiceImpl.getDeptId(id); 
    DepartmentForm departmentForm = new DepartmentForm(); 
    departmentForm.setDeptId(dept.getDeptId()); 
    departmentForm.setName(dept.getName()); 
    model.addAttribute("departmentForm", departmentForm); 
    return "dept_form"; 
  } 
   
@RequestMapping(value=/updatedept.html/{id}",  
    method=RequestMethod.POST) 
public String updateRecordSubmit(Model model,  
  @ModelAttribute("departmentForm") DepartmentForm  
  departmentForm, @PathVariable("id") Integer id ){ 
 
    departmentServiceImpl.updateDepartment( 
      departmentForm, id); 
    model.addAttribute("departments",  
    departmentServiceImpl.readDepartments()); 
    return "dept_result"; 
} 
       } 

After a successful authentication, the AppSecurityConfig will redirect to /deptform.html as the default success page.

  1. Create a LoginController that will provide all the handler methods of the AppSecurityConfig:
@Controller 
public class LoginController { 
 
@RequestMapping(value="/login.html",  
  method=RequestMethod.GET) 
public String login(@RequestParam(name="error",  
  required=false) String error, Model model) { 
 
    try { 
      if (error.equalsIgnoreCase("true")) { 
        String errorMsg = "Login Error"; 
        model.addAttribute("errorMsg", errorMsg); 
      }else{ 
        model.addAttribute("errorMsg", error); 
      } 
    } catch (NullPointerException e) { 
      return "login_form"; 
    } 
    return "login_form"; 
  } 
 
  @RequestMapping("/logout.html") 
  public String logout() { 
    return "logout_form"; 
  } 
   
  @RequestMapping("/after_logout.html") 
  public String afterLogout() { 
    return "after_logout_form"; 
  } 
 
  @RequestMapping("logerr.html") 
  public String logerr() { 
    return "logerr_form"; 
} 
} 

The custom login page /login.html must be configured and recognized by the org.springframework.security.config.annotation.web.builders.HttpSecurity API. Likewise, the /logout.html must be the AppSecurityConfig's custom logout entry which will redirect to /after_logout.html after a successful logout.

  1. Create the views for the /logout.html, /after_logout.html and /login.html. The login transaction must be using the POST HTTP method:
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> 
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> 
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %> 
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%> 
  
<!DOCTYPE html> 
<html> 
<head> 
<meta http-equiv="Content-Type" content="text/html;  
charset=ISO-8859-1"> 
<title><spring:message code="login_title" /></title> 
</head> 
<body> 
  <c:if test="${ not empty errorMsg }"> 
      <em><c:out value='${ errorMsg }'/></em><br/> 
  </c:if> 
  <form action="<c:url value='/login.html' />"  
    method="POST"> 
     <spring:message code="user"  /> 
<input type="text" name="username" /><br/> 
     <spring:message code="password"  /> 
<input type="text" name="password" /><br/> 
     <input type="submit" value="Login" /> 
  </form> 
</body> 
</html> 
  1. Next, create the physical views for the DepartmentController's /deptform.html form and the /dept_result.html result view pages. The form view must be implemented this way:
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> 
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> 
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %> 
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%> 
<!DOCTYPE html> 
<html> 
<head> 
<meta http-equiv="Content-Type" content="text/html;  
charset=ISO-8859-1"> 
<title><spring:message code="dept_title"  /></title> 
</head> 
<body> 
  <c:if test="${ not empty username }"> 
      Username is <em><c:out value='${ username}'/> 
      </em><br/> 
      Password is <em><c:out value='${ password }'/> 
      </em><br/> 
      Role(s) is/are: <em><c:out value='userRole'/> 
      </em><br/> 
  </c:if> 
  <form:form modelAttribute="departmentForm"   
     method="POST"> 
     <spring:message code="dept_id"  /> 
     <form:input path="deptId"  /><br/> 
     <spring:message code="dept_name"  /> 
     <form:input path="name"  /><br/> 
     <input type="submit" value="Add Department" /> 
  </form:form> 
</body> 
</html> 

While the result view looks like this snippet:

<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> 
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> 
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %> 
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%> 
<!DOCTYPE html> 
<html> 
<head> 
<meta http-equiv="Content-Type" content="text/html;  
charset=ISO-8859-1"> 
<title><spring:message code="dept_title"  /></title> 
</head> 
<body> 
   <h1><spring:message code="dept_list"  /></h1> 
   <table border="1"> 
      <c:forEach var="dept" items="${ departments }"> 
            <tr> 
                <td>${ dept.deptId }</td> 
                <td>${ dept.name }</td> 
                <c:url var="delUrl"  
                  value="/deldept.html/${dept.deptId}" /> 
                <td> 
                <a href="<c:out  
                 value='${ delUrl }'/>">DELETE</a></td> 
                <c:url var="updateUrl"  
                 value="/updatedept.html/${dept.id}" /> 
                <td><a href="<c:out  
                  value='${ updateUrl }'/>">UPDATE</a> 
                </td> 
            </tr> 
      </c:forEach> 
   </table> 
  <br> 
<a href="<c:url value='/deptform.html'/>"> 
    Add More Department</a> <br/> 
   <em>This is for CSRF Logout</em> 
<c:url var="logoutUrl" value="/logout.html"/> 
   <form action="${logoutUrl}" method="post"> 
    <input type="submit" value="Log out" /> 
   </form> 
 </body> 
</html> 
  1. Reuse and update the view.properties, messages_en_US.properties configuration for the view mappings and view label bundles, respectively. Also, reuse jdbc.properties for the MySQL connection details. Place all these files in the srcmain esourcesconfig folder.
  2. clean, build, and deploy. Start the application through https://localhost:8443/ch04/login.html. Using the user and password registered in the org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder of AppSecurityConfig context, proceed adding a new department record and try viewing all the records stored. After clicking logout, you will be redirected to the logout success page:
  1. After the logout success page, any controller-defined URL will always redirect users to /login.html view; otherwise, a HTTP Status 404 will be issued.
  2. Try running the application using HTTP at port 8080 and the security model will always redirect it to /login.html, causing HTTP Status 404, because HTTP and port 8080 is not yet mapped to HTTPS and port 8483.
..................Content has been hidden....................

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