Spring Security: Store the hashed password into MySql database

In the previous article, we have extended one step ahead in storing the password for the users in the hashed form using BCrypt hashing algorithm instead of plain text in the spring-security.xml file

Hashed means more secure comparing with plain text, but here still user credentials and ROLES needs to be stored in the xml file which isn’t a feasible solution considering if the application is scalable in the future depending on the business requirements

Dilemma here is – today there is only little number of users but this can grow from thousands to lakhs and keeping all user credentials in the xml file won’t be a good idea

So, move user credentials along with their ROLES in the database. While doing so, remember to store the password in the hashed format – more secure !!

Technology Used

  • Java 1.7
  • Eclipse Luna IDE
  • Spring-4.0.0-RELEASE
  • Apache-Maven-3.2.1
  • Apache Tomcat 7.0.54
  • MySql-connector-java-5.1.31

Mavenize or download required jars

Add Spring-4.0.0 and Spring-security-3.2.0 dependencies to the pom.xml

<dependencies>
		<!-- junit -->
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>3.8.1</version>
			<scope>test</scope>
		</dependency>

		<!-- jstl for jsp page -->
		<dependency>
			<groupId>jstl</groupId>
			<artifactId>jstl</artifactId>
			<version>${jstl.version}</version>
		</dependency>

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

		<!-- MySql-Connector -->
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>5.1.31</version>
		</dependency>

		<!-- Spring 4.0.0.RELEASE Framework -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-core</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-jdbc</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-web</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
			<version>${spring.version}</version>
		</dependency>

		<!-- Spring Security 3.2.0.RELEASE Framework -->
		<dependency>
			<groupId>org.springframework.security</groupId>
			<artifactId>spring-security-core</artifactId>
			<version>${spring.security.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.security</groupId>
			<artifactId>spring-security-web</artifactId>
			<version>${spring.security.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.security</groupId>
			<artifactId>spring-security-config</artifactId>
			<version>${spring.security.version}</version>
		</dependency>
	</dependencies>

Folks who aren’t familiar with Maven concepts or don’t require maven for their project, can download the below jars individually from the spring site and include them in the classpath

  • spring-core-4.0.0-RELEASE
  • spring-context-4.0.0-RELEASE
  • spring-beans-4.0.0-RELEASE
  • spring-aop-4.0.0-RELEASE
  • spring-expression-4.0.0-RELEASE
  • spring-web-4.0.0-RELEASE
  • spring-webmvc-4.0.0-RELEASE
  • spring-jdbc-4.0.0-RELEASE
  • spring-tx-4.0.0-RELEASE
  • spring-security-core-3.2.0-RELEASE
  • spring-security-web-3.2.0-RELEASE
  • spring-security-config-3.2.0-RELEASE
  • mysql-connector-java-5.1.31
  • commons-logging-1.1.1
  • aopalliance-1.0
  • junit-3.8.1
  • jstl-1.2

Directory Structure

Before moving on, let us understand the directory/package structure once you create project in Eclipse IDE
Maven has to follow certain directory structure

  • src/test/java –> test related files, mostly JUnit test cases
  • src/main/java –> create java source files under this folder
  • src/main/resources –> all configuration files placed here
  • Maven Dependencies or Referenced Libraries –> includes jars in the classpath
  • WEB-INF under webapp –> stores web.xml & other configuration files related to web application

Project Structure (Package Explorer view in Eclipse)

1_SpringSecurity_Database_Hashing_Project_Structure_In_Eclipse

Jars Libraries Used in the Project (Maven Dependencies)

2_SpringSecurity_Database_Hashing_Jars_In_Classpath

Web application

For any web application, entry point is web.xml which describes how the incoming http requests are served / processed. Further, it describes about the global-context and local-context param (i.e.; <context-param> & <init-param>) for loading the files particular to project requirements & contains respective listener.

With this introduction, we will understand how we configured web.xml for our Spring Security + Spring MVC application

web.xml (the entry point à under WEB-INF)

This web.xml file describes,

  • all http requests with wild card pattern “/” will be intercepted by the configured servlet called “DispatcherServlet” (org.springframework.web.servlet.DispatcherServlet)
  • </servlet-name> name mentioned in the web.xml is mvc-dispatcher, which on loading/exploding the war into the application server(Tomcat application server for our example) looks for the servlet filename called “mvc-dispatcher-servlet.xml”
  • <context-param> with its attributes describes the location of the file from where it has to be loaded
  • “mvc-dispatcher-servlet.xml” is the file which describes how exactly specific http requests are handled or which controllers gets invoked for certain http requests. We will see “mvc-dispatcher-servlet.xml” file for our Spring MVC + Spring Security application
  • <welcome-file-list> files under this tag is the start-up page
  • Servlet filter called “DelegatingFilterProxy” with url-pattern /* intercepts incoming http requests and enter Spring Security framework for security checks to authenticate users
  • “spring-security.xml” describes which URL needs to be intercepted along with their roles/credentials using MySql dataSource

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" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">

	<!-- project display for web application -->
	<display-name>SpringSecurity</display-name>

	<!-- welcome file list -->
	<welcome-file-list>
		<welcome-file>index.jsp</welcome-file>
	</welcome-file-list>

	<!-- Spring MVC DispatcherServlet: dispatches HTTP requests to registered controllers -->
	<servlet>
		<servlet-name>mvc-dispatcher</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<load-on-startup>1</load-on-startup>
	</servlet>

	<servlet-mapping>
		<servlet-name>mvc-dispatcher</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>

	<!-- location of the root application context xml file -->
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>
			/WEB-INF/mvc-dispatcher-servlet.xml,
            /WEB-INF/spring-security.xml
        </param-value>
	</context-param>

	<!-- context loader listener -->
	<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>
		<dispatcher>REQUEST</dispatcher>
		<dispatcher>FORWARD</dispatcher>
		<dispatcher>INCLUDE</dispatcher>
		<dispatcher>ERROR</dispatcher>
	</filter-mapping>
</web-app>

Dispatcher Servlet

Below mvc-dispatcher-servlet.xml file defines,

  • <context:annotation-config /> to activate annotations for beans registered with the application
  • <context:component-scan base-package=”” /> this tag scans all classes & sub-classes under the value of base-package attribute and register them with the Spring container
  • dataSource bean with driverClassname, url, username and password parameters configured to interact with MySql database
  • this dataSource is used in the spring-security xml file to interact with MySql database for authenticating users for their credentials along with their ROLES
  • other bean element  for view resolver defines the logic for output rendering i.e.; viewName returned by the Controller which will be sandwiched between the prefix (WEB-INF/jsp) & suffix (.jsp)
  • Now, there should be a file under the directory as defined i.e.; (WEB-INF/jsp/<viewName>.jsp
  • otherwise, not found exception thrown

mvc-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-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">

	<!-- to activate annotations in beans already registered in the application context -->
	<context:annotation-config />

	<!-- register beans for handling incoming HTTP requests -->
	<context:component-scan base-package="com.spring.series.security.controller" />

	<!-- view resolver for rendering the final output -->
	<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="prefix">
			<value>/WEB-INF/jsp/</value>
		</property>
		<property name="suffix">
			<value>.jsp</value>
		</property>
	</bean>

	<!-- MySql dataSource configuration -->
	<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/benchresources" />
		<property name="username" value="root" />
		<property name="password" value="" />
	</bean>
</beans>

MySql Database

To move user credentials and their ROLES, you have to create tables and insert records. Let’s do it

Create USERS table

# USERS
create table users (
    username varchar(50) not null primary key,
    password varchar(60) not null,
    enabled boolean not null
) engine = InnoDb;

Create AUTHORITIES table

# AUTHORITIES
create table authorities (
    username varchar(50) not null,
    authority varchar(50) not null,
    foreign key (username) references users (username),
    unique index authorities_idx_1 (username, authority)
) engine = InnoDb;

Let’s insert records in both tables

# INSERT records into USERS table

INSERT INTO `users`(`username`, `password`, `enabled`) VALUES ('Arun', 
'$2a$10$BwyjwGRWc4gMk2Y1e2jzie.FVYrfgxV0.aHgdU1VM6E.Rf0ZYoaWa, 1);
INSERT INTO `users`(`username`, `password`, `enabled`) VALUES ('Jeremy', 
'$2a$10$EHmzwTcEFS1IUZ.hhsMw.uZvG2uwH7fOS1nh/fcIiAvmXg3LwdVP.', 1);
INSERT INTO `users`(`username`, `password`, `enabled`) VALUES ('Jing', 
'$2a$10$twiIh66bjFBWBYZPWOrc1uS/KRCdT61Z5wFdpJGdeHwY2HeCZ.J.a, 1);

# INSERT records into AUTHORITIES table

INSERT INTO authorities (username, authority) VALUES ('Arun', 'ROLE_ADMIN');
INSERT INTO authorities (username, authority) VALUES ('Jeremy', 'ROLE_USER');
INSERT INTO authorities (username, authority) VALUES ('Jing', 'ROLE_USER');

How to get hashed or encoded password using BCryptPasswordEncoder

PasswordHashing.java

package com.spring.series.security;

import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

public class PasswordHashing {

		public static void main(String[] args) {

		String[] originalPassword = {"arun123", "jeremy123", "jing123"};
		PasswordEncoder encoder = new BCryptPasswordEncoder();
		String hashedPassword = "";

		System.out.println("ORIGINAL \t HASHED");
		System.out.println("=========\t=======");
		for(String password : originalPassword){
			hashedPassword = encoder.encode(password);
			System.out.println(password + "\t\t" + hashedPassword);
		}
	}
}

Result in console:

ORIGINAL 	 HASHED
=========	=======
arun123	        $2a$10$BwyjwGRWc4gMk2Y1e2jzie.FVYrfgxV0.aHgdU1VM6E.Rf0ZYoaWa
jeremy123	$2a$10$EHmzwTcEFS1IUZ.hhsMw.uZvG2uwH7fOS1nh/fcIiAvmXg3LwdVP.
jing123	        $2a$10$twiIh66bjFBWBYZPWOrc1uS/KRCdT61Z5wFdpJGdeHwY2HeCZ.J.a

Spring Security Configuration

This Spring Security configuration file describes the security URL to be intercepted and login details for that particular role

  • First element <security:http /> with pattern describes which are all incoming http requests needs to be intercepted
  • Second element with <security:authentication-manager /> defines the credentials (username/password) for every role. For example, ROLE_ADMIN, ROLE_USER, etc
  • <security:password-encoder ref=“bcryptPasswordEncoder” /> refers hashing algorithm used for this application, which is BCryptPasswordEncoder(org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder)
  • bcryptPasswordEncoder bean defines encoding algorithm with two constructor-arg viz. name & strength. Default strength value is 10
  • <security:jdbc-user-service /> defines two queries to authenticate users credentials along with their ROLES, interacting dataSource configured in the mvc-dispatcher-servlet.xml which is MySql database in our example

login-page: this is mapped to custom login page we created for this example
default-target-url: on successful login, this page will be displayed to the user
authentication-failure-url: page will be redirected to this URL for invalid credentials
logout-success-url: on successful logout, page will be redirected to this URL
error-page: page will be directed to this url for unauthorized users

spring-security.xml

<beans:beans xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:security="http://www.springframework.org/schema/security" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd">

	<security:http auto-config="true">
		<security:intercept-url pattern="/admin*" access="ROLE_ADMIN" />
		<security:intercept-url pattern="/home*" access="ROLE_USER" />
		<security:form-login login-page="/login" default-target-url="/admin" authentication-failure-url="/error" />
		<security:access-denied-handler error-page="/403" />
		<security:logout logout-success-url="/logout" />
	</security:http>

	<security:authentication-manager>
		<security:authentication-provider>
			<security:password-encoder ref="bcryptPasswordEncoder" />
			<security:jdbc-user-service data-source-ref="dataSource" users-by-username-query="select username, password, enabled from users where username=?" authorities-by-username-query="select username, authority from authorities where username =? " />
		</security:authentication-provider>
	</security:authentication-manager>

	<beans:bean id="bcryptPasswordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder">
		<beans:constructor-arg name="strength" value="10" />
	</beans:bean>
</beans:beans>

Let’s see coding in action

 

Update the Controller:

First two GET methods are used for business mapping like (“/home*”, “/admin*”)
Whereas other three methods are implemented to authenticate the users before accessing the page (“/login”, “/logout” and “/error”)

“/403” – for unauthorized users (Access is denied)
“/admin*” – this URL is intercepted by spring security framework and will be redirected to the customized login page for admin (ROLE_ADMIN)
“/home*” – this URL is intercepted by spring security framework and will be redirected to the customized login page for other users (ROLE_USER)

HomeController.java

package com.spring.series.security.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 HomeController {

	// http://localhost:8080/SpringSecurity/home
	@RequestMapping(value = "/home", method = RequestMethod.GET)
	public String homePage(ModelMap modelMap) {

		modelMap.addAttribute("topic", "Welcome to the Spring Security Learning");
		modelMap.addAttribute("description", "This is HOME Page");
		return "home";
	}

	// http://localhost:8080/SpringSecurity/admin
	@RequestMapping(value = "/admin", method = RequestMethod.GET)
	public ModelAndView adminPage() {

		ModelAndView modelAndView = new ModelAndView("admin");
		modelAndView.addObject("topic", "Welcome to the Spring Security Learning");
		modelAndView.addObject("description", "This is ADMIN page");
		return modelAndView;
	}

	// to display customized login page to user
	@RequestMapping(value = "/login", method = RequestMethod.GET)
	public ModelAndView loginPage() {

		ModelAndView model = new ModelAndView();
		model.setViewName("login");
		model.addObject("message", "Login with Username and Password");
		return model;
	}

	// on successful logout
	@RequestMapping(value = "/logout", method = RequestMethod.GET)
	public ModelAndView logoutPage() {

		ModelAndView model = new ModelAndView();
		model.setViewName("login");
		model.addObject("message", "Logout successful");
		return model;
	}

	// for invalid username or password
	@RequestMapping(value = "/error", method = RequestMethod.GET)
	public ModelAndView errorPage() {

		ModelAndView model = new ModelAndView();
		model.setViewName("login");
		model.addObject("message", "Invalid Username or Password");
		return model;
	}

	// for 403 access denied page
	@RequestMapping(value = "/403", method = RequestMethod.GET)
	public String accesssDenied(Principal user, ModelMap modelMap) {

		if (user != null) {
			modelMap.addAttribute("topic", "Access denied");
			modelMap.addAttribute("description", "Sorry " + user.getName() + ", you don't have permission to access this page");
		}
		else {
			modelMap.addAttribute("topic", "Access denied");
			modelMap.addAttribute("description", "Sorry, you don't have permission to access this page");
		}
		return "accessdenied";
	}
}

View Technologies (JSP Pages)

 

This is the customized login page that will be rendered to the user to KEY-IN credentials (username/password) for the protected access

It is important to note few variables to understand the spring security custom login form. Variables such as j_spring_security_check’, j_username, j_password in the below login.jsp are predefined in the spring security framework and we shouldn’t modify it, otherwise it won’t work as expected.
login.jsp (\src\main\webapp\WEB-INF\jsp\login.jsp)

<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Spring Security</title>
</head>
<body>
	<center>

<h1>Welcome to Spring Security Learning</h1>


<div style="text-align: center; padding: 30px; border: 1px solid; width: 250px;">

<form method="post"
				action="<c:url value='j_spring_security_check' />">

<table>

<tr>

<td colspan="2" style="color: red">${message}</td>

					</tr>


<tr>

<td>User Name:</td>


<td><input type="text" name="j_username" /></td>

					</tr>


<tr>

<td>Password:</td>


<td><input type="password" name="j_password" /></td>

					</tr>


<tr>

<td colspan="1"><input type="submit" value="Login" /></td>


<td colspan="1"><input name="reset" type="reset" /></td>

					</tr>

				</table>

			</form>

		</div>

	</center>
</body>
</html>

 

This is default page under webapp for direct access
index.jsp (\src\main\webapp\index.jsp)

<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<!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=ISO-8859-1">
<title>Spring Security</title>
</head>
<body>
	<center>
		<b>Welcome to the Spring Security Learning</b>

<h2>This is default page</h2>

	</center>
</body>
</html>

 

This is home page with two messages to display and this will be intercepted by spring security framework and only authorized users can access this page. We have configured in such a way that only users with role (ROLE_USER) will be authorized to access
home.jsp (\src\main\webapp\WEB-INF\jsp\home.jsp)

<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Spring Security</title>
</head>
<body>
	<center>
		<b>${topic}</b>

<h2>${description}</h2>


<h3>
			<a href="<c:url value="/j_spring_security_logout" />">Logout</a>
		</h3>

	</center>
</body>
</html>

 

This is admin page with protected access i.e.; only admin role (ROLE_ADMIN) can access this page with correct credentials. Additionally, we got Logout link (j_spring_security_logout) to allow the logged-in user to get logged-out and disable the current session
admin.jsp (\src\main\webapp\WEB-INF\jsp\admin.jsp)

<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Spring Security</title>
</head>
<body>
	<center>
		<b>${topic}</b>

<h2>${description}</h2>


<h3>
			<a href="<c:url value="/j_spring_security_logout" />">Logout</a>
		</h3>

	</center>
</body>
</html>

 

HTTP Status 403 – Access is denied (customizing)
accessdenied.jsp (\src\main\webapp\WEB-INF\jsp\accessdenied.jsp)

<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<!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=ISO-8859-1">
<title>Spring Security</title>
</head>
<body>
	<center>
		<b>${topic}</b>

<h2>${description}</h2>

	</center>
</body>
</html>

Time to Test/Execute

 

User credentials and their ROLES

Sr. No Username Password ROLE
1 arun arun123 ROLE_ADMIN
2 jing jing123 ROLE_USER
3 jeremy jeremy123 ROLE_USER

This means user arun can access admin page whereas other can access home page (just for testing purpose)

 

Enter URL: http://localhost:8080/SpringSecurityDatabase/admin into web browser
You will get to view the customized login page
3_SpringSecurity_Database_admin_url

 

 

As this is “/admin*” url, only users with admin role i.e.; ROLE_ADMIN authorized to access this page
Enter admin arun’s credential to check whether we can access this page or not.
4_SpringSecurity_Database_admin_url_success_login

 

 

See what if Jing try to access this page who is having ROLE_USER role, URL will be redirected to “/403” for access denied
5_SpringSecurity_Database_admin_url_failure_for_ROLE_USER

 

 

Enter URL: http://localhost:8080/SpringSecurityDatabase/home into web browser
6_SpringSecurity_Database_home_url

 

 

Enter Jeremy’s credentials who is having role ROLE_USER
7_SpringSecurity_Database_home_url_success_login

 

 

Now, we will access this page with admin role
8_SpringSecurity_Database_home_url_failure_for_ROLE_ADMIN

 

Conclusion: Storing hashed password into database helps the application to be more scalable in the future considering number of users might grow

Download project

Spring-Security-Store-hashed-password-into-MySql-database (6kB)

 

Read Also:

 

Happy Coding !!
Happy Learning !!

Spring Security: Hashing the password