In this Spring Boot example, we will discuss inMemoryAuthentication in Spring Security along with custom login, logout JSP pages.
Java 8
JSP
Maven 3.5.0
Spring Boot 2.4.4
Spring Boot Actuator 2.4.4
MySQL connector 8.0.23
MySQL 8.0
Red Hat JBoss Developer Studio 11.3.0.GA / Eclipse
<?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.example</groupId>
<artifactId>spring-boot-security-custom-login-page</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>spring-boot-security-custom-login-page</name>
<description>microservice for accessing employee's operations using mysql db</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.4</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</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-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
# Management
server:
port: 8080
servlet.context-path: /spring-boot-security-custom-login-page/
endpoints:
hawtio:
enabled: true
jolokia:
enabled: true
management:
endpoints:
web:
exposure:
include: info, health, metrics, hawtio, env
base-path: /monitoring
endpoint:
health:
show-details: always
info:
app:
spring-boot-security-custom-login-page
description:This is a microservice for springboot application testing
## Application Name
camel:
springboot:
name: spring-boot-security-custom-login-page
spring.datasource.url: jdbc:mysql://localhost/bootdb
spring.datasource.username: root
spring.datasource.password: admin
spring.datasource.platform: mysql
spring.mvc.view.prefix: /WEB-INF/jsp/
spring.mvc.view.suffix: .jsp
CREATE DATABASE bootdb;
USE bootdb;
CREATE TABLE employee (empId VARCHAR(10) NOT NULL, empName VARCHAR(100) NOT NULL);
Spring Boot SpringApplication class is used to bootstrap and launch a Spring application from a Java main method. This class automatically creates the ApplicationContext from the classpath, scan the configuration classes and launch the application. This class is very helpful in launching Spring MVC or Spring REST application using Spring Boot.
package com.the.basic.tech.info;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringBootFormHandingApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootFormHandingApplication.class, args);
}
}
package com.the.basic.tech.info.controllers;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
import com.the.basic.tech.info.model.Employee;
import com.the.basic.tech.info.service.EmployeeService;
@Controller
public class EmployeeController {
@Autowired
EmployeeService employeeService;
@RequestMapping("/welcome")
public ModelAndView firstPage() {
return new ModelAndView("welcome");
}
@RequestMapping(value = "/addNewEmployee", method = RequestMethod.GET)
public ModelAndView show() {
return new ModelAndView("addEmployee", "emp", new Employee());
}
@RequestMapping(value = "/addNewEmployee", method = RequestMethod.POST)
public ModelAndView processRequest(@ModelAttribute("emp") Employee emp) {
employeeService.insertEmployee(emp);
List<Employee> employees = employeeService.getAllEmployees();
ModelAndView model = new ModelAndView("getEmployees");
model.addObject("employees", employees);
return model;
}
@RequestMapping("/getEmployees")
public ModelAndView getEmployees() {
List<Employee> employees = employeeService.getAllEmployees();
ModelAndView model = new ModelAndView("getEmployees");
model.addObject("employees", employees);
return model;
}
@RequestMapping(value = "/login", method = RequestMethod.GET)
public String login(Model model, String error, String logout) {
if (error != null)
model.addAttribute("errorMsg", "Your username and password are invalid.");
if (logout != null)
model.addAttribute("msg", "You have been logged out successfully.");
return "login";
}
}
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<c:set var="contextPath" value="${pageContext.request.contextPath}"/>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
<meta name="description" content="">
<meta name="author" content="">
<title>Log in with your account</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
</head>
<body>
<div class="container">
<form method="POST" action="${contextPath}/login" class="form-signin">
<h2 class="form-heading">Log in</h2>
<div class="form-group ${error != null ? 'has-error' : ''}">
<span>${msg}</span>
<input name="username" type="text" class="form-control" placeholder="Username"
autofocus="true"/>
<input name="password" type="password" class="form-control" placeholder="Password"/>
<span>${errorMsg}</span>
<button class="btn btn-lg btn-primary btn-block" type="submit">Log In</button>
</div>
</form>
</div>
<!-- /container -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script></body>
</html>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<c:set var="contextPath" value="${pageContext.request.contextPath}"/>
<div style="border: 1px solid #ccc; padding: 5px; margin-bottom: 20px;">
<a href="${contextPath}/welcome">Home</a> |
<a href="${contextPath}/addNewEmployee">Add
Employee</a> | <a href="${pageContext.request.contextPath}/getEmployees">Show
Employees</a> | <u><h2 style="color: blue;">
<a onclick="document.forms['logoutForm'].submit()">Logout</a>
</h3></u>
<form id="logoutForm" method="POST" action="${contextPath}/logout">
</form>
</div>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<c:set var="contextPath" value="${pageContext.request.contextPath}"/>
<%@page session="false"%>
<html>
<head>
<title>Welcome</title>
</head>
<body>
<jsp:include page="menu.jsp" />
<h3 style="color: blue;">Hello Admin</h3>
</body>
</html>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<c:set var="contextPath" value="${pageContext.request.contextPath}"/>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Add Employee</title>
</head>
<jsp:include page="menu.jsp" />
<body>
<h3 style="color: blue;">Add New Employee</h3>
<div id="addEmployee">
<form:form action="${contextPath}/addNewEmployee" method="post"
modelAttribute="emp">
<p>
<label>Enter Employee Id</label>
<form:input path="empId" />
</p>
<p>
<label>Enter Name</label>
<form:input path="empName" />
</p>
<input type="SUBMIT" value="Submit" />
</form:form>
</div>
</body>
</html>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<c:set var="contextPath" value="${pageContext.request.contextPath}"/>
<%@page session="false"%>
<html>
<head>
<title>Show Employees</title>
</head>
<body>
<jsp:include page="menu.jsp" />
<h3 style="color: blue;">Show All Employees</h3>
<ul>
<c:forEach var="listValue" items="${employees}">
<li>${listValue}</li>
</c:forEach>
</ul>
</body>
</html>
package com.the.basic.tech.info.config;
import org.springframework.beans.factory.annotation.Autowired;
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.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@Configuration
@EnableWebSecurity
public class EmployeeSecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/resources/**");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/").permitAll().antMatchers("/welcome").hasAnyRole("USER", "ADMIN")
.antMatchers("/getEmployees").hasAnyRole("USER", "ADMIN").antMatchers("/addNewEmployee")
.hasAnyRole("ADMIN").anyRequest().authenticated().and().formLogin().loginPage("/login").permitAll()
.and().logout().permitAll();
http.csrf().disable();
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder authenticationMgr) throws Exception {
authenticationMgr.inMemoryAuthentication().withUser("admin").password("{noop}admin").authorities("ROLE_USER","ROLE_ADMIN").and()
.withUser("test").password("{noop}test").authorities("ROLE_USER");
}
}
package com.the.basic.tech.info.dao;
import java.util.List;
import com.the.basic.tech.info.model.Employee;
public interface EmployeeDao {
void insertEmployee(Employee cus);
void insertEmployees(List<Employee> employees);
List<Employee> getAllEmployees();
Employee getEmployeeById(String empId);
}
package com.the.basic.tech.info.dao.impl;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.annotation.PostConstruct;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BatchPreparedStatementSetter;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.support.JdbcDaoSupport;
import org.springframework.stereotype.Repository;
import com.the.basic.tech.info.dao.EmployeeDao;
import com.the.basic.tech.info.model.Employee;
@Repository
public class EmployeeDaoImpl extends JdbcDaoSupport implements EmployeeDao{
@Autowired
DataSource dataSource;
@PostConstruct
private void initialize(){
setDataSource(dataSource);
}
@Override
public void insertEmployee(Employee emp) {
String sql = "INSERT INTO employee " +
"(empId, empName) VALUES (?, ?)" ;
getJdbcTemplate().update(sql, new Object[]{
emp.getEmpId(), emp.getEmpName()
});
}
@Override
public void insertEmployees(final List<Employee> employees) {
String sql = "INSERT INTO employee " + "(empId, empName) VALUES (?, ?)";
getJdbcTemplate().batchUpdate(sql, new BatchPreparedStatementSetter() {
public void setValues(PreparedStatement ps, int i) throws SQLException {
Employee employee = employees.get(i);
ps.setString(1, employee.getEmpId());
ps.setString(2, employee.getEmpName());
}
public int getBatchSize() {
return employees.size();
}
});
}
@Override
public List<Employee> getAllEmployees(){
String sql = "SELECT * FROM employee";
List<Map<String, Object>> rows = getJdbcTemplate().queryForList(sql);
List<Employee> result = new ArrayList<Employee>();
for(Map<String, Object> row:rows){
Employee emp = new Employee();
emp.setEmpId((String)row.get("empId"));
emp.setEmpName((String)row.get("empName"));
result.add(emp);
}
return result;
}
@Override
public Employee getEmployeeById(String empId) {
String sql = "SELECT * FROM employee WHERE empId = ?";
return (Employee)getJdbcTemplate().queryForObject(sql, new Object[]{empId}, new RowMapper<Employee>(){
@Override
public Employee mapRow(ResultSet rs, int rwNumber) throws SQLException {
Employee emp = new Employee();
emp.setEmpId(rs.getString("empId"));
emp.setEmpName(rs.getString("empName"));
return emp;
}
});
}
}
package com.the.basic.tech.info.model;
public class Employee {
private String empId;
private String empName;
public String getEmpId() {
return empId;
}
public void setEmpId(String empId) {
this.empId = empId;
}
public String getEmpName() {
return empName;
}
public void setEmpName(String empName) {
this.empName = empName;
}
@Override
public String toString() {
return "Employee [empId=" + empId + ", empName=" + empName + "]";
}
}
package com.the.basic.tech.info.service;
import java.util.List;
import com.the.basic.tech.info.model.Employee;
public interface EmployeeService {
void insertEmployee(Employee emp);
void insertEmployees(List<Employee> employees);
List<Employee> getAllEmployees();
void getEmployeeById(String empid);
}
package com.the.basic.tech.info.service.impl;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.the.basic.tech.info.dao.EmployeeDao;
import com.the.basic.tech.info.model.Employee;
import com.the.basic.tech.info.service.EmployeeService;
@Service
public class EmployeeServiceImpl implements EmployeeService {
@Autowired
EmployeeDao employeeDao;
@Override
public void insertEmployee(Employee employee) {
employeeDao.insertEmployee(employee);
}
@Override
public void insertEmployees(List<Employee> employees) {
employeeDao.insertEmployees(employees);
}
public List<Employee> getAllEmployees() {
return employeeDao.getAllEmployees();
}
@Override
public void getEmployeeById(String empId) {
Employee employee = employeeDao.getEmployeeById(empId);
System.out.println(employee);
}
}
Login Url: http://localhost:8080/spring-boot-security-custom-login-page/login
Log in as test/test user and try to access Add New Employee
Note: You will get below 403-Forbidden Error page, because only admin users can access this operation.
Enjoy 🙂 … have a great day !!!