Introduction

The example Spring Boot Security form based authentication will show you how to use custom login form with Spring’s j_spring_security_check to authenticate a user. You may also look into form based authentication on Spring MVC framework. The similar example we will implement here but using Spring Boot framework. In the previous example we have also used Resource Bundle that will also help you to make your application internationalization.

Prerequisites

Eclipse Neon, Java 1.8, Gradle 5.4.1, Spring Boot 2.1.6

Go through the below sections to implement Spring Boot Security form based authentication.

Creating Project

Create a gradle based project in Eclipse. The project name is given as spring-boot-security-form-based-authentication.

Adding Dependencies

Once the gradle project gets created in Eclipse, open build.gradle script in editor and update to include the required dependencies.

We have added Spring Boot web starter, security starter for our web application with security implementation.

We have also added jasper and jstl as we will use jsp pages as a view technology in our application.

buildscript {
	ext {
		springBootVersion = '2.1.6.RELEASE'
	}
    repositories {
    	mavenLocal()
    	mavenCentral()
    }
    dependencies {
    	classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
    }
}

apply plugin: 'java'
apply plugin: 'org.springframework.boot'
    
sourceCompatibility = 1.8
targetCompatibility = 1.8

repositories {
	mavenLocal()
    mavenCentral()
}

dependencies {
	compile("org.springframework.boot:spring-boot-starter-web:${springBootVersion}")
	compile("org.springframework.boot:spring-boot-starter-security:${springBootVersion}")
	compile('org.apache.tomcat.embed:tomcat-embed-jasper:9.0.22')
    compile('javax.servlet:jstl:1.2')
}

Configuring View Resolvers

Add application.properties file under src/main/resources to configure view resolvers. You can also create bean as a view resolver but specifying in the application.properties is fair enough for the Spring Boot application.

So we will put our jsp files under webapp/views folder and the jsp file’s extension is .jsp.

spring.mvc.view.prefix=/views/
spring.mvc.view.suffix=.jsp

Creating Config Class

We need to create Java config class to configure Spring Security for our form based authentication.

I have put comments after each line in the below Spring Security configuration class to understand it clearly.

The below WebSecurityConfigclass, which is responsible for all security configurations, extends WebSecurityConfigurerAdapter and overrides configure(HttpSecurity http) and authenticationManager() methods. We have also ignored security for static resources such as js, css, images etc that have path /static**, root path /, /login, /error. We have overridden method configure(HttpSecurity http) to apply security for all URLs including the URL which is having pattern /admin with role as ADMIN.

Here, the in-memory authentication has been provided. Ideally in the application, the authentication should happen through database or LDAP or any other third party API etc.

We have used PasswordEncoder because plain text password is not acceptable in current version of Spring Security and you will get below exception if you do not use PasswordEncoder.

java.lang.IllegalArgumentException: There is no PasswordEncoder mapped for the id "null"
	at org.springframework.security.crypto.password.DelegatingPasswordEncoder$UnmappedIdPasswordEncoder.matches(DelegatingPasswordEncoder.java:244)

As the passwords are in encrypted format in the below class, so you won’t find it easier until I tell you. The password for admin is admin.

package com.jeejava.spring.boot.security.form.based.authentication.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.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;

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

	@Autowired
	public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
		auth.inMemoryAuthentication().passwordEncoder(passwordEncoder()).withUser("admin")
				.password("$2a$10$dl8TemMlPH7Z/mpBurCX8O4lu0FoWbXnhsHTYXVsmgXyzagn..8rK").roles("ADMIN"); // password -
																											// admin
	}

	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http// ,
				.authorizeRequests()// , authorize request
				.antMatchers("/", "/login", "/static/**", "/error**").permitAll().anyRequest().authenticated()// ,
																												// ignore
																												// /,login
																												// page,static
				// resources, error
				// pages
				.antMatchers("/admin")// Ensures that request with "/admin" to
										// our application requires the user to
										// be authenticated
				.access("hasRole('ADMIN')")// Any URL that starts with
											// "/admin" will
				// be restricted to users who have the
				// role "ROLE_ADMIN",
				.and()// ,
				.formLogin()// Allows users to authenticate with form based
							// login,
				.loginPage("/login")// specifies the location of the log in
									// page,
				.loginProcessingUrl("/j_spring_security_check")// login
																// processing
																// URL,
				.defaultSuccessUrl("/admin")// default-target-url,
				.failureUrl("/login?error")// authentication-failure-url,
				.usernameParameter("username")// overrides Spring's default
												// j_username with
												// username-parameter,
				.passwordParameter("password");// overrides Spring's default
												// j_password with
												// password-parameter
	}

	@Bean
	public PasswordEncoder passwordEncoder() {
		return new BCryptPasswordEncoder();
	}

}

Creating REST Controller

Now create below REST Controller class to test Spring Boot Security form based authentication.

We have defined few end-points in the below REST controller class, where the path / and /login do not need to be authenticated and only /admin needs to be authenticated.

package com.jeejava.spring.boot.security.form.based.authentication.controller;

import javax.servlet.http.HttpServletRequest;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
public class SpringSecurityController {

	@GetMapping("/")
	public String defaultPage(Model model) {
		model.addAttribute("msg", "Welcome to Spring Security");
		return "index";
	}

	@GetMapping("/login")
	public String loginPage(Model model, @RequestParam(value = "error", required = false) String error,
			@RequestParam(value = "logout", required = false) String logout) {
		if (error != null) {
			model.addAttribute("error", "Invalid Credentials");
		}
		if (logout != null) {
			model.addAttribute("msg", "You have been successfully logged out");
		}
		return "login";
	}

	@GetMapping("/logout")
	public String logoutPage(Model model, HttpServletRequest request) {
		request.getSession().invalidate();
		return "redirect:/login?logout";
	}

	@GetMapping("/admin")
	public String adminPage(Model model) {
		model.addAttribute("title", "Administrator Control Panel");
		model.addAttribute("message", "This page demonstrates how to use Spring security");
		return "admin";
	}

}

Creating View Files

We will create three view files, i.e., jsp pages for path – /, /login and /admin.

Path – /

Create index.jsp file under src/main/webapp/views folder with the below content.

It will just show you home page that has a link to go to the Admin page.

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
	pageEncoding="ISO-8859-1"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Spring Security Basic - Form Based Authentication</title>
</head>
<body>
	<div align="center">
		<h1>Home Page</h1>
		<a href="${pageContext.request.contextPath}/admin">Go to Administrator page</a>
	</div>
</body>
</html>

Path – /login

Create a file login.jsp under src/main/webapp/views folder with below content.

This page shows you login form when you click on Go to Administrator page link on home page.

In this page you need to put admin/admin as credentials to go to the admin page otherwise you will get login error.

<%@ page language="java" session="true"
	contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
<head>
<title>Spring Security Basic - Form Based Authentication</title>
<link rel="stylesheet" type="text/css"
	href="<c:url value="/static/css/style.css"/>" />
</head>
<body>
	<div id="login-box">
		<h2>Login Here</h2>
		<c:if test="${not empty error}">
			<div class="error">${error}</div>
		</c:if>
		<c:if test="${not empty msg}">
			<div class="msg">${msg}</div>
		</c:if>
		<form name='loginForm'
			action="<c:url value='j_spring_security_check' />" 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 colspan='2'><input name="submit" type="submit"
						value="Submit" /></td>
				</tr>
			</table>
			<input type="hidden" name="${_csrf.parameterName}"
				value="${_csrf.token}" />
		</form>
	</div>
</body>
</html>

Path – /admin

Create a file admin.jsp page under src/main/webapp/views folder with below content.

This page shows admin page once you successfully logged in to the application using login page.

In this page you will see your username and logout link with some message. On clicking on the logout link you will be redirected to the login page with successful message.

<%@ page language="java" session="true"
	contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<%@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 Basic - Form Based Authentication</title>
</head>
<body>
	<div align="center">
		<h1>${title}</h1>
		<h2>${message}</h2>
		<c:if test="${pageContext.request.userPrincipal.name != null}">
			<h2>
				Welcome
				: ${pageContext.request.userPrincipal.name} | <a
					href="<c:url value='logout'/>">Logout</a>
			</h2>
		</c:if>
	</div>
</body>
</html>

Applying Style

Now we apply some basic style for our pages. So create below style.css file under src/main/webapp/static/css folder.

.error {
	padding: 15px;
	margin-bottom: 20px;
	border: 1px solid transparent;
	border-radius: 4px;
	color: #a94442;
	background-color: #f2dede;
	border-color: #ebccd1;
}

.msg {
	padding: 15px;
	margin-bottom: 20px;
	border: 1px solid transparent;
	border-radius: 4px;
	color: #31708f;
	background-color: #d9edf7;
	border-color: #bce8f1;
}

#login-box {
	width: 500px;
	padding: 20px;
	margin: 50px auto;
	background: #fff;
	-webkit-border-radius: 2px;
	-moz-border-radius: 2px;
	border: 1px solid #000;
}

Creating Main Class

Creating a main would be sufficient to deploy our application into the Tomcat server. This is a great advantage that you just need to let Spring know that it is your Spring Boot Application using @SpringBootApplication and main class.

package com.jeejava.spring.boot.security.form.based.authentication;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication(scanBasePackages = "com.jeejava.spring.boot.security.form.based.authentication")
public class SpringSecurityFormBasedAuthApp {

	public static void main(String[] args) {
		SpringApplication.run(SpringSecurityFormBasedAuthApp.class, args);
	}

}

Deploying the Application

Just run the above main class to deploy the application into embedded Tomcat server. The server will start on default port 8080.

Testing the Application

Home Page

When you hit the URL http://localhost:8080/, you will see below page on the browser:

spring boot security form based authentication

Login Page

When you click on the Go to Administrator page, you will be redirected to the login page because admin page is secured and must be authenticated.

Credentials – admin/admin

spring boot security form based authentication

Admin Page

Once you successfully logged in to the application, you will see below admin page.

spring boot security form based authentication

Login Page – Error

If you input invalid username and password then you will see below page:

spring boot security form based authentication

Logout – Success

When you successfully logged out of the admin page by clicking on the logout link, then you will be redirected to the login page with success message.

spring boot security form based authentication

Source Code

You can download source code.

Thanks for reading.

Tags:

Leave a Reply

Your email address will not be published. Required fields are marked *