spring security database authentication example

In previous post, we have already seen  how to use custom login page in Spring security. We have declared username and password in spring-security.xml but what if you want to read it from database. In most of the cases, we will read credentials from database.
In this post, we will do authentication using database. We will use MySQL and hibernate for database authentication.
If you want to secure your spring web application , you just need to configure some files to make it happen using spring security. We will apply login security on hello world example, so when only authorised users will be able to access admin page.
Before going ahead, lets first configure database table in mysql which we will use for authentications.

Database setup:

CREATE  TABLE users (
  username VARCHAR(45) NOT NULL ,
  password VARCHAR(45) NOT NULL ,
  active TINYINT NOT NULL DEFAULT 1 ,
  PRIMARY KEY (username));
   
CREATE TABLE user_roles (
  user_role_id int(11) NOT NULL AUTO_INCREMENT,
  username varchar(45) NOT NULL,
  role varchar(45) NOT NULL,
  PRIMARY KEY (user_role_id),
  UNIQUE KEY unique_username_role (role,username),
  KEY fk_username_index (username),
  CONSTRAINT fk_username FOREIGN KEY (username) REFERENCES users (username));
 
INSERT INTO users(username,password,active)
VALUES ('arpit','arpit', true);
INSERT INTO users(username,password,active)
VALUES ('john','john', true);
 
INSERT INTO user_roles (username, role)
VALUES ('arpit', 'ROLE_USER');
INSERT INTO user_roles (username, role)
VALUES ('arpit', 'ROLE_ADMIN');
INSERT INTO user_roles (username, role)
VALUES ('john', 'ROLE_USER');
Here are steps to apply spring security custom login form on spring mvc hello world example.
Step 1: 
Create Spring mvc hello world example named SpringSecurityDatabaseAuthenticationExample. It will create basic spring mvc application.
Step 2: 
Add spring security, hibernate and mysql connector to pom.xml. You need to add following dependencies to the pom.
pom.xml 
<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/maven-v4_0_0.xsd">
 <modelVersion>4.0.0</modelVersion>
 <groupId>com.arpit.java2blog</groupId>
 <artifactId>SpringSecurityDatabaseAuthenticationExample</artifactId>
 <packaging>war</packaging>
 <version>0.0.1-SNAPSHOT</version>
 <name>SpringSecurityDatabaseAuthenticationExample Maven Webapp</name>
 <url>http://maven.apache.org</url>
 <dependencies>
  <dependency>
   <groupId>junit</groupId>
   <artifactId>junit</artifactId>
   <version>3.8.1</version>
   <scope>test</scope>
  </dependency>

  <dependency>
   <groupId>javax.servlet</groupId>
   <artifactId>javax.servlet-api</artifactId>
   <version>3.1.0</version>
  </dependency>

  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-core</artifactId>
   <version>${spring.version}</version>
  </dependency>
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-webmvc</artifactId>
   <version>${spring.version}</version>
  </dependency>
  <!-- Spring Security -->
  <dependency>
   <groupId>org.springframework.security</groupId>
   <artifactId>spring-security-core</artifactId>
   <version>${security.version}</version>
  </dependency>

  <dependency>
   <groupId>org.springframework.security</groupId>
   <artifactId>spring-security-web</artifactId>
   <version>${security.version}</version>
  </dependency>

  <dependency>
   <groupId>org.springframework.security</groupId>
   <artifactId>spring-security-config</artifactId>
   <version>${security.version}</version>
  </dependency>

  <dependency>
   <groupId>jstl</groupId>
   <artifactId>jstl</artifactId>
   <version>1.2</version>
   <scope>provided</scope>
  </dependency>
  <!-- Hibernate -->
  <dependency>
   <groupId>org.hibernate</groupId>
   <artifactId>hibernate-core</artifactId>
   <version>${hibernate.version}</version>
  </dependency>
  <dependency>
   <groupId>org.hibernate</groupId>
   <artifactId>hibernate-entitymanager</artifactId>
   <version>${hibernate.version}</version>
  </dependency>

  <!-- Apache Commons DBCP -->
  <dependency>
   <groupId>commons-dbcp</groupId>
   <artifactId>commons-dbcp</artifactId>
   <version>1.4</version>
  </dependency>
  <!-- Spring ORM -->
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-orm</artifactId>
   <version>${spring.version}</version>
  </dependency>
  <dependency>
   <groupId>mysql</groupId>
   <artifactId>mysql-connector-java</artifactId>
   <version>5.1.6</version>
  </dependency>
 </dependencies>
 <build>
  <finalName>SpringSecurityHelloWorlExample</finalName>
  <plugins>
   <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.1</version>
    <configuration>
     <source>${jdk.version}</source>
     <target>${jdk.version}</target>
    </configuration>
   </plugin>
  </plugins>
 </build>
 <properties>
  <spring.version>4.2.1.RELEASE</spring.version>
  <security.version>4.0.3.RELEASE</security.version>
  <hibernate.version>4.3.5.Final</hibernate.version>
  <jdk.version>1.7</jdk.version>
 </properties>
</project>

Create Controller  and view

Step 3
Change controller class named "HelloWorldController.java" as below
package org.arpit.java2blog.springmvc.controller;

import java.security.Principal;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class HelloWorldController {

 @RequestMapping("/helloworld")
 public ModelAndView hello(ModelMap model,Principal principal) {

  String loggedInUserName=principal.getName();
  
  return new ModelAndView("hello", "userName", loggedInUserName);
 }
 
 @RequestMapping("/admin")
 public ModelAndView helloAdmin(ModelMap model,Principal principal) {

  String loggedInUserName=principal.getName();
  
  return new ModelAndView("admin", "userName", loggedInUserName);
 }

 @RequestMapping(value="/login", method = RequestMethod.GET)
 public String login(ModelMap model) {

  return "login";

 }
 
 @RequestMapping(value="/loginError", method = RequestMethod.GET)
 public String loginError(ModelMap model) {
  model.addAttribute("error", "true");
  return "login";
 }
 
 // for 403 access denied page
  @RequestMapping(value = "/403", method = RequestMethod.GET)
  public ModelAndView accesssDenied(Principal user) {

   ModelAndView model = new ModelAndView();
   if (user != null) {
    model.addObject("msg", "Hi " + user.getName()
    + ", You can not access this page!");
   } else {
    model.addObject("msg",
    "You can not access this page!");
   }

   model.setViewName("403");
   return model;
  }
}
As  request first goes to dispatcherServlet and it redirects to controller class. Here @Controller depicts that this is our controller class. @RequestMapper is used to map incoming http request to handler method(hello() in above controller).So hello() method of HelloWorldController.java will handle GET request from dispatcher.
Here We have used Principal object to get current logged in username. It is set by Spring security framework.
Step 4: 
Modify hello.jsp in /WEB-INF/pages folder
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>  
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Hello</title>
</head>
<body>
${message}
<c:url value="/j_spring_security_logout" var="logoutUrl" />
<a href="${logoutUrl}">Log Out</a>
 
</body>
</html>
Step 5:
Create login.jsp in /WEB-INF/pages folder
 <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>  
<html>
<style type="text/css">
<%@include file="style.css" %>
</style>
<head>
<title>Custom Login Page</title>
</head>
<body onload='document.loginForm.j_username.focus();'>
<h3>Custom Login Page</h3>
 
<%
 
String errorString = (String)request.getAttribute("error");
if(errorString != null && errorString.trim().equals("true")){
out.println("<span class=\"dark\">Incorrect login name or password. Please try again");
}
%>
 
<form name='loginForm' action="<c:url value='login' />""
method='POST'>
 
<table>
<tr>
<td>User:</td>
<td><input type='text' name='username' value=''>
</td>
</tr>
<tr>
<td>Password:</td>
<td><input type='password' name='password' />
</td>
</tr>
<tr>
<td><input name="submit" type="submit"
value="submit" />
</td>
<td><input name="reset" type="reset" />
</td>
</tr>
</table>
 
</form>
</body>
</html>
We have used css file in above login.jsp. Create style.css file as below.
#header
{
font-size:40px;
}
.dark
{
color:red;
}
Step 6:
Create admin.jsp in /WEB-INF/pages folder.
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>  
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Hello Admin</title>
</head>
<body>
hello ${userName} !!!
You are the admin

<c:url value="/j_spring_security_logout" var="logoutUrl" />
<a href="${logoutUrl}">Log Out</a>
 
</body>
</html>

Step 7: Create 403.jsp in /WEB-INF/pages folder.
 <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>  
<html>
<body>
 <h1>HTTP Status 403 - Access is denied</h1>
<h2>${msg}</h2>
<c:url value="/j_spring_security_logout" var="logoutUrl" />
<a href="${logoutUrl}">Log Out</a>
</body>
</html>
Step 8:  
Now we need to add spring configuration xml. Create a file named spring-security.xml.
<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-4.0.xsd
    http://www.springframework.org/schema/security
    http://www.springframework.org/schema/security/spring-security-4.0.xsd">

 <http auto-config="true" use-expressions="true">
  <intercept-url pattern="/resources/**" access="permitAll" />
  <intercept-url pattern="/hello*"
   access="hasAnyRole('ROLE_ADMIN','ROLE_USER')" />
  <intercept-url pattern="/admin**" access="hasRole('ROLE_ADMIN')" />
  <form-login login-page="/login" default-target-url="/helloworld"
   authentication-failure-url="/loginError" />
  <logout logout-success-url="/" logout-url="/j_spring_security_logout" />
  <csrf disabled="true" />
  <access-denied-handler error-page="/403" />
 </http>
 <authentication-manager>
  <authentication-provider>
   <jdbc-user-service data-source-ref="dataSource"
    users-by-username-query="select username, password, active from users where username=?"
    authorities-by-username-query="select username, role from user_roles where username=?" />
  </authentication-provider>
 </authentication-manager>
</beans:beans>
We have used form-login in above file, so if user tries to access any secured url, he will be authenticated based on above form-login configuration.
Lets understand meaning of each attribute of form-login tag
login-page : we need to provide url for login page.
default-target-url : here if authentication is successful, then target page url should be provided.
authentication-failure-url : if authentication is unsuccessful, then redirection page url should be provided here.
access-denied-handler : If user don't have access to the page, /403 url will be called.
intercept-url configure for which pattern what kind of security is configured. For example: If http request url has pattern /hello*(hello.jsp,helloworld.html), it will be accessed to ROLE_ADMIN and ROLE_USER but if http request url has pattern /admin*,it will be accessed to ROLE_ADMIN only

We have provided queries for users-by-username-query and authorities-by-username-query to set up credentials for roles.
Step 9: 
springmvc-dispatcher-servlet.xml
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:context="http://www.springframework.org/schema/context"
 xmlns:mvc="http://www.springframework.org/schema/mvc" 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-3.0.xsd http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">

<context:component-scan base-package="org.arpit.java2blog.springmvc.controller" />
 <bean
  class="org.springframework.web.servlet.view.InternalResourceViewResolver">
  <property name="prefix">
   <value>/WEB-INF/pages/</value>
  </property>
  <property name="suffix">
   <value>.jsp</value>
  </property>
 </bean>
 <mvc:annotation-driven/>

 <bean id="dataSource"
  class="org.springframework.jdbc.datasource.DriverManagerDataSource">
  <property name="driverClassName" value="com.mysql.jdbc.Driver" />
  <property name="url" value="jdbc:mysql://localhost:3306/CountryData" />
  <property name="username" value="root" />
  <property name="password" value="arpit123" />
 </bean>

 <!-- Hibernate 4 SessionFactory Bean definition -->
 <bean id="hibernate4AnnotatedSessionFactory"
  class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
  <property name="dataSource" ref="dataSource" />
  <property name="hibernateProperties">
   <props>
    <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect
    </prop>
    <prop key="hibernate.show_sql">true</prop>
   </props>
  </property>
 </bean>
</beans>
Step 10: We need to change in web.xml to configure spring security.
<?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" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0">
  <display-name>Archetype Created Web Application</display-name>
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
  <servlet>
    <servlet-name>springmvc-dispatcher</servlet-name>
    <servlet-class>
   org.springframework.web.servlet.DispatcherServlet
        </servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>springmvc-dispatcher</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>
   <context-param>
  <param-name>contextConfigLocation</param-name>
  <param-value>
   /WEB-INF/springmvc-dispatcher-servlet.xml,
   /WEB-INF/spring-security.xml
  </param-value>
 </context-param>
 
 <listener>
  <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
 </listener>

 <!-- Spring Security -->
 <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>
Here we have used DelegatingFilterProxy which intercepts http request and pass it to springSecurityFilterChain. springSecurityFilterChain is a bean created by spring with http element used in spring-security.xml. It maintains list of all filters and is responsible for chain of filters.

We are done with changes required for spring security.

Step 11:
It's time for maven build.
   
Provide goals as clean install (given below) and click on run


Run the application

Step 12: Right click on project -> run as -> run on server
Select apache tomcat and click on finish
   You will see below screen:
Spring Security database authentication

When you click on admin page link, you will get following login page. Now put User as arpit and password also as arpit.
Spring Security login
We have put correct username and password , so we will see below screen.
Spring security admin login

If you use user john to access admin page, you will get below screens.
Spring security john login
As john don't have access to admin page, so you will get below screen.

Download source code:

click to begin
20KB .zip
Please comment if you have any issues with above post.

Written by Arpit:

If you have read the post and liked it. Please connect with me on Facebook | Twitter | Google Plus

 

Java tutorial for beginners Copyright © 2012