Spring MVC 4 Security + Hibernate 5 + MySQL using Annotation + XML Example

By Arvind Rai, February 16, 2017
This page will walk through spring MVC 4 security + hibernate 5 + MySQL using annotation + XML example. Spring security has the UserDetailsService interface that loads user from the given source. We can access user profile using hibernate as usual as we do in spring hibernate integration. The user profile with username, password and roles will be used by loadUserByUsername() method in the UserDetailsService implementation class. In our demo application we will use MySQL database. We will create two separate application, one using JavaConfig and second using XML configuration. In our JavaConfig based application, we will create separate JavaConfig for spring MVC, spring security and for spring database integration using hibernate and in this way we will get better configuration understanding. In XML configuration based application again we will create separate XML files for spring MVC, spring security and for spring database integration using hibernate. For authentication we will create a custom login page. Our JSP files will be using CSRF protection. In service layer we will create a secured method. To populate data from database we have DAO layer. In our application we will use HibernateTemplate to query database. We will handle access denied exception and redirect on an error page. LocalSessionFactoryBean will be used to create session factory. For data source we will use BasicDataSource of commons.dbcp2 library. For password encoding we will use BCrypt password encoding. Now find the complete example step by step.

Software Used

We are using following software in our example.
1. Java 8
2. Spring 4.3
3. Hibernate 5
4. Gradle 3.3
5. Maven 3.3
6. Tomcat 8.0
7. MySQL 5.5
8. Eclipse Mars

Gradle and Maven to Build the Project

Find the gradle file to build the project.
build.gradle
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'war'
war.archiveName 'spring-app.war'
repositories {
    mavenCentral()
}
dependencies {
    compile 'org.springframework.boot:spring-boot-starter-web:1.5.1.RELEASE'
    compile 'org.springframework.boot:spring-boot-starter-data-jpa:1.5.1.RELEASE'
    compile 'org.springframework.boot:spring-boot-starter-security:1.5.1.RELEASE'
    compile 'org.hibernate:hibernate-core:5.2.6.Final'
    compile 'mysql:mysql-connector-java:6.0.5'
    compile 'org.apache.commons:commons-dbcp2:2.1.1'
    compile 'jstl:jstl:1.2'
    providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat:1.5.1.RELEASE'    
}  
Find the maven file to build the project.
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.concretepage</groupId>
	<artifactId>spring-demo</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>war</packaging>
	<name>SpringSecurity</name>
	<description>Spring Demo Project</description>
	<parent>
	    <groupId>org.springframework.boot</groupId>
  	    <artifactId>spring-boot-starter-parent</artifactId>
	    <version>1.5.1.RELEASE</version>
 	    <relativePath/>
	</parent>
	<properties>
	    <java.version>1.8</java.version>
	    <context.path>spring-app</context.path>
	</properties>
	<dependencies>
	  <dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-web</artifactId>
	  </dependency>
	  <dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-data-jpa</artifactId>
	  </dependency>
	  <dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-security</artifactId>
	  </dependency>
	  <dependency>
		 <groupId>org.hibernate</groupId>
		 <artifactId>hibernate-core</artifactId>
		 <version>5.2.6.Final</version>
	  </dependency>
	  <dependency>
		 <groupId>mysql</groupId>
		 <artifactId>mysql-connector-java</artifactId>
		 <version>6.0.5</version>
	  </dependency>	  	  	  
	  <dependency>
		 <groupId>org.apache.commons</groupId>
		 <artifactId>commons-dbcp2</artifactId>
		 <version>2.1.1</version>
	  </dependency>    	  	  	  
          <dependency>
	         <groupId>jstl</groupId>
	         <artifactId>jstl</artifactId>
	         <version>1.2</version>
          </dependency>
	  <dependency>
		 <groupId>org.springframework.boot</groupId>
		 <artifactId>spring-boot-starter-tomcat</artifactId>
		 <scope>provided</scope>
	  </dependency>      
	</dependencies>
	<build>
	  <plugins>
	    <plugin>
		  <groupId>org.apache.maven.plugins</groupId>
		  <artifactId>maven-war-plugin</artifactId>
		  <version>3.0.0</version>
		  <configuration>
			 <warName>${context.path}</warName>
		  </configuration>
	    </plugin>
	  </plugins>
	</build>
</project>  

MySQL Database and Java Entity for Hibernate

We are using MySQL database in our demo application. We will create a table for user profile that will contain columns such as user name, password, role etc. For the demo we have inserted three users as mahesh/m123, trump/t123 with ROLE_ADMIN and one more user that is arvind/a123 with ROLE_USER in our database. Find the database schema.
Database Schema using MySQL
-- Dumping database structure for concretepage
CREATE DATABASE IF NOT EXISTS `concretepage`; 
USE `concretepage`;
-- Dumping structure for table concretepage.users
CREATE TABLE IF NOT EXISTS `users` (
  `username` varchar(50) NOT NULL,
  `password` varchar(100) NOT NULL,
  `full_name` varchar(100) NOT NULL,
  `role` varchar(50) NOT NULL,
  `country` varchar(100) NOT NULL,
  `enabled` tinyint(1) NOT NULL,
  PRIMARY KEY (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
-- Dumping data for table concretepage.users: ~3 rows (approximately)
INSERT INTO `users` (`username`, `password`, `full_name`, `role`, `country`, `enabled`) VALUES
	('arvind', '$2a$10$Vfs8YMQx1YHI.d0x4WO8n.C.K3prfllnP2uS/j8ChpRirS17y.N42', 'Arvind Rai', 'ROLE_USER', 'India', 1),
	('mahesh', '$2a$10$N0eqNiuikWCy9ETQ1rdau.XEELcyEO7kukkfoiNISk/9F7gw6eB0W', 'Mahesh Sharma', 'ROLE_ADMIN', 'India', 1),
	('trump', '$2a$10$QifQnP.XqXDW0Lc4hSqEg.GhTqZHoN2Y52/hoWr4I5ePxK7D2Pi8q', 'Donald Trump', 'ROLE_ADMIN', 'US', 1); 
For user password encoding we are using BCrypt password encoder. It can be maximum 72 characters long, so we should keep our password column accordingly. I am using password column length as 100. If we do not set the proper length of password column then while saving BCrypt encoded password, it will be truncated and hence the user will never be authenticated because of wrong password. To create BCrypt password, we can use a simple main class.
Main.java
package com.concretepage;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
public class Main {
	public static void main(String[] args) {
		BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
		System.out.println(encoder.encode("m123"));
	}
}
Now find the java entity for the users table.
UserInfo.java
package com.concretepage.entity;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name="users")
public class UserInfo implements Serializable {
	private static final long serialVersionUID = 1L;
	@Id
	@Column(name="username")
	private String userName;
	@Column(name="password")
	private String password;
	@Column(name="role")	
	private String role;
	@Column(name="full_name")	
	private String fullName;
	@Column(name="country")	
	private String country;
	@Column(name="enabled")	
	private short enabled;
	public String getUserName() {
		return userName;
	}
	public void setUserName(String userName) {
		this.userName = userName;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}
	public String getRole() {
		return role;
	}
	public void setRole(String role) {
		this.role = role;
	}
	public String getFullName() {
		return fullName;
	}
	public void setFullName(String fullName) {
		this.fullName = fullName;
	}
	public String getCountry() {
		return country;
	}
	public void setCountry(String country) {
		this.country = country;
	}
	public short getEnabled() {
		return enabled;
	}
	public void setEnabled(short enabled) {
		this.enabled = enabled;
	}
} 

Spring MVC 4 Security + Hibernate 5 + MySQL using Annotation

Here we will discuss the steps to create spring MVC 4 security + hibernate 5 + MySQL using annotation. We will create separate JavaConfig files for spring MVC, spring security and spring database configuration using hibernate. We have service layer, DAO layer and controller. For login, we will create a custom login page. Let us start step by step.

1. Project Structure using JavaConfig in Eclipse

Find the project structure using JavaConfig in eclipse.
Spring MVC 4 Security + Hibernate 5 + MySQL using Annotation + XML Example

2. Spring MVC Configuration

Find the Spring MVC configuration file. We are creating a bean of InternalResourceViewResolver that will help controller to access file which are put inside WEB-INF folder. Find the configuration file.
AppConfig.java
package com.concretepage.config;  
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
@Configuration 
@ComponentScan("com.concretepage") 
@EnableWebMvc   
public class AppConfig {  
    @Bean  
    public InternalResourceViewResolver viewResolver() {  
	InternalResourceViewResolver resolver = new InternalResourceViewResolver();  
        resolver.setPrefix("/WEB-INF/secure/");  
        resolver.setSuffix(".jsp");
        return resolver;  
    }
}  
It is good practice to keep view files inside WEB-INF because from this location it cannot be directly accessed by using URL on browser. These files can only be accessed by controllers using InternalResourceViewResolver . It has methods such as setPrefix() and setSuffix(). setPrefix() sets the prefix and setSuffix() sets the suffix the view name to form a URL.
@EnableWebMvc is annotated at class level with @Configuration annotation. @EnableWebMvc imports spring MVC configuration from WebMvcConfigurationSupport.
@ComponentScan annotation is used to configure component scanning directive. Here we have specified the directive as com.concretepage . All the components within this package and its child packages will be scanned.
Now we need to register DispatcherServlet. When we are using JavaConfig then preferred way to register DispatcherServlet is as follows.
WebAppInitializer.java
package com.concretepage.config;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer  {
	@Override
	protected Class<?>[] getRootConfigClasses() {
		 return new Class[] { AppConfig.class };
	}
	@Override
        protected Class<?>[] getServletConfigClasses() {
                 return null;
        }
        @Override
        protected String[] getServletMappings() {
                 return new String[]{ "/" };
        } 
} 
We need to specify our configuration file in the method getRootConfigClasses().

3. Spring Security Configuration

For spring security configuration find the following JavaConfig.
SecurityConfig.java
package com.concretepage.config;  
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import com.concretepage.service.MyAppUserDetailsService;
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled=true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
	@Autowired
	private MyAppUserDetailsService myAppUserDetailsService;
	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http.authorizeRequests()
		.antMatchers("/user/**").hasAnyRole("ADMIN","USER")
		.and().formLogin()  //login configuration
                .loginPage("/customLogin.jsp")
                .loginProcessingUrl("/appLogin")
                .usernameParameter("app_username")
                .passwordParameter("app_password")
                .defaultSuccessUrl("/user/home")	
		.and().logout()    //logout configuration
		.logoutUrl("/appLogout") 
		.logoutSuccessUrl("/customLogin.jsp")
		.and().exceptionHandling() //exception handling configuration
		.accessDeniedPage("/user/error");
	} 	
        @Autowired
	public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
                auth.userDetailsService(myAppUserDetailsService).passwordEncoder(passwordEncoder());
	}
        @Bean
        public PasswordEncoder passwordEncoder() {
    	        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
    	        return passwordEncoder;
        }
}   
We need to annotate our security configuration class with @EnableWebSecurity that helps to configure spring security from WebSecurityConfigurer class. To override any security method we need to extend WebSecurityConfigurerAdapter class. We have overridden configure() method from WebSecurityConfigurerAdapter class. configure() method is used to configure HttpSecurity class. Within this method we are performing spring security login, logout and exception handling configuration.
In spring security using JavaConfig, CSRF protection is enabled by default. CSRF protection is Cross Site Request Forgery. If we want to disable it we can do it using http.csrf().disable() .
To authenticate user, we will use custom UserDetailsService which in turn will use hibernate ORM to interact with database. Using configureGlobal() we will configure our custom UserDetailsService instance. For this purpose spring security provides AuthenticationManagerBuilder. Here we also configure password encoder.
In our example we are using BCryptPasswordEncoder for password encoding. It uses BCrypt strong hashing function. While instantiating BCryptPasswordEncoder we can optionally pass strength or we can also pass SecureRandom instance to its constructor. The default strength is 10.
In our example we are using @Secured annotation to secure service layer. This annotation will only be effective if we use @EnableGlobalMethodSecurity with the attribute securedEnabled=true annotated at class level with @Configuration annotation.
Now we need to register DelegatingFilterProxy to use the springSecurityFilterChain before any other registered Filter. We can do it as follows. Find the spring security initializer.
SecurityInitializer.java
package com.concretepage.config;
import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;
public class SecurityInitializer extends AbstractSecurityWebApplicationInitializer {
} 
The above code also registers spring ContextLoaderListener that is responsible to startup and shut down spring root web application context.

4. Database Configuration

We will integrate hibernate with our spring MVC security using JavaConfig as follows.
DBConfig.java
package com.concretepage.config;
import java.io.IOException;
import java.util.Properties;
import javax.sql.DataSource;
import org.apache.commons.dbcp2.BasicDataSource;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.orm.hibernate5.HibernateTemplate;
import org.springframework.orm.hibernate5.HibernateTransactionManager;
import org.springframework.orm.hibernate5.LocalSessionFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@Configuration 
@EnableTransactionManagement
@PropertySource("classpath:database.properties")
public class DBConfig {
	@Autowired
        private Environment env;	
	@Bean
	public HibernateTemplate hibernateTemplate() {
	      return new HibernateTemplate(sessionFactory());
	}
 	@Bean
	public SessionFactory sessionFactory() {
	      LocalSessionFactoryBean lsfb = new LocalSessionFactoryBean();
	      lsfb.setDataSource(getDataSource());
	      lsfb.setPackagesToScan("com.concretepage.entity");
	      lsfb.setHibernateProperties(hibernateProperties());
	      try {
		     lsfb.afterPropertiesSet();
	      } catch (IOException e) {
		     e.printStackTrace();
	      }
	      return lsfb.getObject();
	}
        @Bean
	public DataSource getDataSource() {
	     BasicDataSource dataSource = new BasicDataSource();
	     dataSource.setDriverClassName(env.getProperty("database.driverClassName"));
	     dataSource.setUrl(env.getProperty("database.url"));
	     dataSource.setUsername(env.getProperty("database.username"));
	     dataSource.setPassword(env.getProperty("database.password"));
	     return dataSource;
	}
	@Bean
	public HibernateTransactionManager hibernateTransactionManager(){
	     return new HibernateTransactionManager(sessionFactory());
	}
        private Properties hibernateProperties() {
             Properties properties = new Properties();
             properties.put("hibernate.dialect", env.getProperty("hibernate.dialect"));
             properties.put("hibernate.show_sql", env.getProperty("hibernate.show_sql"));
             properties.put("hibernate.format_sql", env.getProperty("hibernate.format_sql"));
             return properties;        
        }	
} 
We have annotated our configuration class with @EnableTransactionManagement that enables annotation-driven transaction management capability in spring. For hibernate transaction management, spring has HibernateTransactionManager class. It allows one thread-bound session per factory. To enable HibernateTransactionManager we have to create a bean of it in our configuration file.
To create a data source, we are using third party library commons-dbcp2. For basic implementation we are using BasicDataSource class of commons-dbcp2. We need to instantiate this class and set the database configuration related value such as driver class name, URL, username and password. In our example we are using MySQL database. To configure hibernate properties we have created a method that returns java Properties loaded with hibernate properties such as hibernate.dialect, hibernate.show_sql etc.
For hibernate SessionFactory we need to instantiate spring LocalSessionFactoryBean. Using LocalSessionFactoryBean we configure data source, packages to scan entity and hibernate properties.
Create a bean of HibernateTemplate. This is a helper class that is used to interact with database. It automatically converts hibernate exceptions to data access exceptions. In DAO class we will use HibernateTemplate methods to get data from database.
@PropertySource annotation accesses the property file and data is loaded to Environment and then by calling its method getProperty() we fetch properties defined in property file. Now find the property file used in our example.
database.properties
database.driverClassName=com.mysql.cj.jdbc.Driver
database.url=jdbc:mysql://localhost:3306/concretepage
database.username=root
database.password=

hibernate.dialect = org.hibernate.dialect.MySQLDialect
hibernate.show_sql = true 
hibernate.format_sql = true 
Here we have externalized database and hibernate properties. Database username and password values are our local values for demo. You need to change it according to your database envoromnet.

5. User Authentication using Spring UserDetailsService

Spring has UserDetailsService interface that loads user specific data. We need to create a class and implement UserDetailsService for user authentication. It has a method loadUserByUsername() that accepts user name and returns
org.springframework.security.core.userdetails.UserDetails 
Now find our class which is implementing UserDetailsService.
MyAppUserDetailsService.java
package com.concretepage.service;
import java.util.Arrays;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import com.concretepage.dao.UserDAO;
import com.concretepage.entity.UserInfo;
@Service
public class MyAppUserDetailsService implements UserDetailsService {
	@Autowired
	private UserDAO userDAO;
	@Override
	public UserDetails loadUserByUsername(String userName)
			        throws UsernameNotFoundException {
		UserInfo activeUserInfo = userDAO.getActiveUser(userName);
		GrantedAuthority authority = new SimpleGrantedAuthority(activeUserInfo.getRole());
		UserDetails userDetails = (UserDetails)new User(activeUserInfo.getUserName(),
				activeUserInfo.getPassword(), Arrays.asList(authority));
		return userDetails;
	}
} 

6. Create DAO and Service Class

Here we are creating a DAO method that will return user profile for a given user name. Here we are using hibernateTemplate.find() method that executes an HQL query. Find the DAO class.
UserDAO.java
package com.concretepage.dao;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.orm.hibernate5.HibernateTemplate;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import com.concretepage.entity.UserInfo;
@Repository
@Transactional
public class UserDAO {
	@Autowired
	private HibernateTemplate hibernateTemplate;
	public UserInfo getActiveUser(String userName) {
		UserInfo activeUserInfo = new UserInfo();
		short enabled = 1;
		List<?> list = hibernateTemplate.find("FROM UserInfo WHERE userName=? and enabled=?",
				userName, enabled);
		if(!list.isEmpty()) {
			activeUserInfo = (UserInfo)list.get(0);
		}
		return activeUserInfo;
	}
} 
When user enters the user name and password to login into the application then getActiveUser() method is used by MyAppUserDetailsService to load the user for authentication and authorization.
@Transactional annotation is used make DAO methods transactional. This annotation can be used at class level as well as method level. It has attributes to define propagation, transaction isolation level etc. We can configure these values as follows.
@Transactional(propagation = Propagation.REQUIRES_NEW, isolation= Isolation.READ_COMMITTED) 
If we do not use any attribute then their default values will be applied. Now find our service layer.
IUserService.java
package com.concretepage.service;
import org.springframework.security.access.annotation.Secured;
import com.concretepage.entity.UserInfo;
public interface IUserService {
	@Secured ({"ROLE_ADMIN"})
	UserInfo getDataByUserName(String userName);
} 
UserService.java
package com.concretepage.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.concretepage.dao.UserDAO;
import com.concretepage.entity.UserInfo;
@Service
public class UserService implements IUserService {
	@Autowired
	private UserDAO userDAO;
	public UserInfo getDataByUserName(String userName) {
		return userDAO.getActiveUser(userName);
	}
} 
We have a secured method in our service layer. To make a method secure, spring has @Secured annotation. The service layer method getDataByUserName() can be accessed by an authenticated user with ROLE_ADMIN . @Secured annotation is effective only if we use below annotation in our spring security configuration class.
@EnableGlobalMethodSecurity(securedEnabled=true) 
If we want to enable more than one user role to access our service layer method then we can do it as follows.
@Secured ({"ROLE_ADMIN", "ROLE_USER"})
UserInfo getDataByUserName(String userName); 
Now the above method can be accessed by both roles ROLE_ADMIN and ROLE_USER.

7. Spring MVC Controller

Find the MVC controller used in our example.
UserController.java
package com.concretepage.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import com.concretepage.service.IUserService;
@Controller
@RequestMapping("/user")
public class UserController {
	@Autowired
	private  IUserService service;
	@RequestMapping(value="/home")
	public String home(ModelMap model, Authentication authentication) {
		authentication.getPrincipal();
		model.addAttribute("user", service.getDataByUserName(authentication.getName()));
 		return "user-info";
 	}
	@RequestMapping(value="/error")
	public String error() {
 		return "access-denied";
 	}
}	 
Here we have created two methods. The method home() will be called after successful authentication and the method error() will be called when an authenticated user tries to access service layer secured method and throws access denied exception.

8. Create Views

Find the spring security login page. We have created a custom login page with CSRF protection.
customLogin.jsp
<html>
    <head>
        <title>Spring 4 Security Example</title>
    </head>
    <body>
       <h3>Spring 4 Security Example</h3>
        <font color="red">
	        ${SPRING_SECURITY_LAST_EXCEPTION.message}
        </font>
	<form action="<%=request.getContextPath()%>/appLogin" method="POST">
		Enter UserName:	<input type="text" name="app_username"/><br/><br/>
		Enter Password: <input type="password" name="app_password"/> <br/><br/>			
		<input type="submit" value="Login"/>
		<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>			
	</form>
    <body>
</html>  
To handle CSRF protection, first we should enable it in our security configuration that is by default enabled and then create a hidden field in view files. Hidden field will have a CSRF parameter name and CSRF token as given above in the custom login page.
After successful login, a user will access service layer. If the user role is authorized to access service layer, then user will get page which will display user information. Find the JSP page that will be used to display user information.
WEB-INF\secure\user-info.jsp
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<html>
    <head>
        <title>Spring 4 Security Example</title>
    </head>
    <body>
      <h3>Logged In User Detail</h3>
      <table>
        <tr><td>Name</td><td><c:out value="${user.fullName}"/></td></tr>
        <tr><td>Role</td><td><c:out value="${user.role}"/></td></tr>
        <tr><td>Country</td><td><c:out value="${user.country}"/></td></tr>
      </table>      
      <form action="<%=request.getContextPath()%>/appLogout" method="POST">
        <input type="submit" value="Logout"/>
        <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>		
      </form>      
    </body>
</html>  
If the user role is not authorized to access service layer then access denied message will be displayed by the following page.
WEB-INF\secure\access-denied.jsp
<html>
    <head>
        <title>Spring 4 Security Example</title>
    </head>
    <body>
      <h3>You are not authorized to access user profile.</h3>
      <form action="<%=request.getContextPath()%>/appLogout" method="POST">
        <input type="submit" value="Logout"/>
        <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>		
      </form> 
    </body>
</html> 

Spring MVC 4 Security + Hibernate 5 + MySQL using XML Configuration

Here we will discuss the steps to create spring MVC 4 security + hibernate 5 + MySQL using XML configuration. We will create separate XML files for spring MVC, spring security and spring database configuration using hibernate. Service layer, DAO layer, controller and views will be same as given in the application using annotation. Let us start now to understand XML configuration.

1. Project Structure using XML Configuration in Eclipse

Find the project structure using XML configuration in eclipse.
Spring MVC 4 Security + Hibernate 5 + MySQL using Annotation + XML Example

2. Spring MVC XML Configuration

Find the spring MVC XML configuration.
dispatcher-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans     
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context.xsd">
        
	<context:component-scan base-package="com.concretepage" />
	<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
	  <property name="prefix" value="/WEB-INF/secure/"/>
	  <property name="suffix" value=".jsp"/> 
        </bean>
</beans> 
<context:component-scan> plays the role to scan components. We need to specify base package. All the components of this package and sub packages will be scanned. Annotation configuration will be true by default.
To access views which lie within the folder WEB-INF, we need to configure InternalResourceViewResolver. Specify prefix and suffix that will be used to create URL for views. To keep view files within WEB-INF is good practice because it cannot be accessed through URL directly from browser but it can be accessed only by controller classes.

3. Spring Security XML Configuration

Find the XML based security configuration.
security-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
	xmlns:beans="http://www.springframework.org/schema/beans" 
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans.xsd
	http://www.springframework.org/schema/security
	http://www.springframework.org/schema/security/spring-security.xsd">
	<http>
		<intercept-url  pattern="/user/**" access="hasAnyRole('ROLE_ADMIN','ROLE_USER')" />
		<form-login 
		   login-page="/customLogin.jsp" 
		   login-processing-url="/appLogin"
		   username-parameter="app_username"
		   password-parameter="app_password"
		   default-target-url="/user/home"/>
		<logout 
		   logout-url="/appLogout" 
		   logout-success-url="/customLogin.jsp"/>  
		<access-denied-handler error-page="/user/error"/>
	</http>
	<beans:bean name="bcryptEncoder"
	      class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"/>	
	<beans:bean name="myAppUserDetailsService"
	      class="com.concretepage.service.MyAppUserDetailsService"/>
	<beans:bean name="userService"
	      class="com.concretepage.service.UserService"/>	      
	<authentication-manager>
		<authentication-provider user-service-ref="myAppUserDetailsService">
		    <password-encoder ref="bcryptEncoder"/>
		</authentication-provider>
	</authentication-manager>
	<global-method-security secured-annotations="enabled" />
</beans:beans>  
<http> is the container element for HTTP security configuration. More than one <http> element can be defined with a specific pattern. We can use auto-config="true" for default login and logout. If we want to customize it then we should use <form-login> and <logout> sub element within <http> element. To handle access denied exception for a secured service layer, we should use <access-denied-handler> element to configure an error page. Spring security version 4 onwards, CSRF protection is enabled by default in XML configuration. We can disable it by using sub element <csrf disabled="true"/> within <http> element.
<authentication-manager> element registers spring AuthenticationManager and <authentication-provider> element specifies user service used in our spring security.
<global-method-security> element plays the role to secure methods for all the beans which are registered in our spring application context. The attribute secured-annotations="enabled" enables the @Secured annotation used with the methods.

4. Database XML Configuration

Find the database configuration for hibernate using XML namespace.
db-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/tx 
        http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context.xsd">

	<context:property-placeholder location="classpath:database.properties"/> 
	<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close">
		<property name="driverClassName" value="${database.driverClassName}" />
		<property name="url" value="${database.url}" />
		<property name="username" value="${database.username}" />
		<property name="password" value="${database.password}" />
	</bean>
	<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
	        <property name="dataSource" ref="dataSource"/>
	        <property name="hibernateProperties">
		  <props>
		    <prop key="hibernate.dialect">${hibernate.dialect}</prop>
		    <prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
		    <prop key="hibernate.format_sql">${hibernate.format_sql}</prop>			   
		  </props>
	        </property>
                <property name="packagesToScan" value="com.concretepage.entity"></property> 
	</bean>
	<bean id="transactionManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager">
	        <property name="sessionFactory" ref="sessionFactory" />
	</bean>
	<bean id="hibernateTemplate" class="org.springframework.orm.hibernate5.HibernateTemplate">
		<constructor-arg name="sessionFactory" ref="sessionFactory"/>  
	</bean>	
	<bean class="com.concretepage.dao.UserDAO" />
	<tx:annotation-driven transaction-manager="transactionManager" /> 		
</beans>  
For data source we are using BasicDataSource of commons.dbcp2 library. <context:property-placeholder> is used to read the database properties from a property file. Create a session factory with LocalSessionFactoryBean using data source and hibernate properties. Using session factory create a bean for transaction manager with HibernateTransactionManager . Using session factory we will also create a bean for HibernateTemplate that will be used to query the database. Now configure transaction manager for annotation driven transaction management.

5. web.xml

Find the web.xml for spring MVC security.
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
    http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">

	<display-name>Spring 4 Security Example</display-name>
	<context-param>
	    <param-name>contextConfigLocation</param-name>
	    <param-value>
	       /WEB-INF/dispatcher-servlet.xml
	       /WEB-INF/security-config.xml
	       /WEB-INF/db-config.xml
	    </param-value>		    
	</context-param>	
	<servlet>
		<servlet-name>dispatcher</servlet-name>
		<servlet-class>
		    org.springframework.web.servlet.DispatcherServlet
		</servlet-class>
		<load-on-startup>1</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>dispatcher</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>
	<!-- Spring Security Configuration -->
	<filter>
		<filter-name>springSecurityFilterChain</filter-name>
		<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
	</filter>
	<filter-mapping>
		<filter-name>springSecurityFilterChain</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
</web-app>  
Spring DispatcherServlet works as central dispatcher for HTTP request controllers. It dispatches the HTTP request to registered handler for processing it, mapping URLs and exception handlings. Now configure ContextLoaderListener to listen startup and shutdown spring root web application context. We will also configure DelegatingFilterProxy filter that works as a proxy for standard servlet filter delegating to spring-managed bean. Now all calls to filter will be delegated to that bean in spring context.

Run Application

To build and run the demo application, follow the steps.
1. Import database in MySQL given above on this page.
2. Download the source code from the link given below on this page.
3. Go to the root directory of the project using command prompt.
4. Build the project using gradle with following command.
gradle clean build 
We can find WAR file in the build\libs directory. If we want to build the project using maven, use following command.
mvn clean package 
We can find WAR file in the target directory.
5. Deploy the WAR file using tomcat and access the URL as given below.
http://localhost:8080/spring-app/user/home 
A login page will open. Find the print screen.
Spring MVC 4 Security + Hibernate 5 + MySQL using Annotation + XML Example
Enter a user credential with role ROLE_ADMIN such as mahesh/m123 or trump/t123. Suppose I am entering trump/t123 credential. User will be able to see profile. Find the print screen.
Spring MVC 4 Security + Hibernate 5 + MySQL using Annotation + XML Example
If we enter a user credential with role ROLE_USER then that user will not be successful to see profile because in the service layer the method getDataByUserName() from the IUserService.java interface is secured and authorized only to ROLE_ADMIN. For the demo we have a user arvind/a123 with ROLE_USER in our database. Now login using this credential. Find the print screen of the output.
Spring MVC 4 Security + Hibernate 5 + MySQL using Annotation + XML Example


I am done now. Happy Spring Security learning!

Reference

Spring Security Reference

Download Source Code

POSTED BY
ARVIND RAI
ARVIND RAI
LEARN MORE








©2024 concretepage.com | Privacy Policy | Contact Us