Create a Login Application with Spring Boot, Spring Security, Spring JDBC
1. Objective of Example
This document is based on:
Spring Boot 2.x
Spring Security
Spring JDBC
Thymeleaf
Database: MySQL, SQL Server, Oracle, Postgres
In this post, I will guide you for creating a Login application using Spring Boot + Spring Security + JDBC + Thymeleaf and explain the operating principle of Spring Security.

Users are required to log in, they can view the protected pages:

The users who have logged in the system is allowed to view only pages within their scope and role. If they access the protected pages located beyond their role, they will be denied.

2. Prepare Database

MySQL
-- Create table
create table APP_USER
(
USER_ID BIGINT not null,
USER_NAME VARCHAR(36) not null,
ENCRYTED_PASSWORD VARCHAR(128) not null,
ENABLED BIT not null
) ;
--
alter table APP_USER
add constraint APP_USER_PK primary key (USER_ID);
alter table APP_USER
add constraint APP_USER_UK unique (USER_NAME);
-- Create table
create table APP_ROLE
(
ROLE_ID BIGINT not null,
ROLE_NAME VARCHAR(30) not null
) ;
--
alter table APP_ROLE
add constraint APP_ROLE_PK primary key (ROLE_ID);
alter table APP_ROLE
add constraint APP_ROLE_UK unique (ROLE_NAME);
-- Create table
create table USER_ROLE
(
ID BIGINT not null,
USER_ID BIGINT not null,
ROLE_ID BIGINT not null
);
--
alter table USER_ROLE
add constraint USER_ROLE_PK primary key (ID);
alter table USER_ROLE
add constraint USER_ROLE_UK unique (USER_ID, ROLE_ID);
alter table USER_ROLE
add constraint USER_ROLE_FK1 foreign key (USER_ID)
references APP_USER (USER_ID);
alter table USER_ROLE
add constraint USER_ROLE_FK2 foreign key (ROLE_ID)
references APP_ROLE (ROLE_ID);
-- Used by Spring Remember Me API.
CREATE TABLE Persistent_Logins (
username varchar(64) not null,
series varchar(64) not null,
token varchar(64) not null,
last_used timestamp not null,
PRIMARY KEY (series)
);
--------------------------------------
insert into App_User (USER_ID, USER_NAME, ENCRYTED_PASSWORD, ENABLED)
values (2, 'dbuser1', '$2a$10$PrI5Gk9L.tSZiW9FXhTS8O8Mz9E97k2FZbFvGFFaSsiTUIl.TCrFu', 1);
insert into App_User (USER_ID, USER_NAME, ENCRYTED_PASSWORD, ENABLED)
values (1, 'dbadmin1', '$2a$10$PrI5Gk9L.tSZiW9FXhTS8O8Mz9E97k2FZbFvGFFaSsiTUIl.TCrFu', 1);
---
insert into app_role (ROLE_ID, ROLE_NAME)
values (1, 'ROLE_ADMIN');
insert into app_role (ROLE_ID, ROLE_NAME)
values (2, 'ROLE_USER');
---
insert into user_role (ID, USER_ID, ROLE_ID)
values (1, 1, 1);
insert into user_role (ID, USER_ID, ROLE_ID)
values (2, 1, 2);
insert into user_role (ID, USER_ID, ROLE_ID)
values (3, 2, 2);
---
SQL Server
-- Create table
create table APP_USER
(
USER_ID BIGINT not null,
USER_NAME VARCHAR(36) not null,
ENCRYTED_PASSWORD VARCHAR(128) not null,
ENABLED BIT not null
) ;
--
alter table APP_USER
add constraint APP_USER_PK primary key (USER_ID);
alter table APP_USER
add constraint APP_USER_UK unique (USER_NAME);
-- Create table
create table APP_ROLE
(
ROLE_ID BIGINT not null,
ROLE_NAME VARCHAR(30) not null
) ;
--
alter table APP_ROLE
add constraint APP_ROLE_PK primary key (ROLE_ID);
alter table APP_ROLE
add constraint APP_ROLE_UK unique (ROLE_NAME);
-- Create table
create table USER_ROLE
(
ID BIGINT not null,
USER_ID BIGINT not null,
ROLE_ID BIGINT not null
);
--
alter table USER_ROLE
add constraint USER_ROLE_PK primary key (ID);
alter table USER_ROLE
add constraint USER_ROLE_UK unique (USER_ID, ROLE_ID);
alter table USER_ROLE
add constraint USER_ROLE_FK1 foreign key (USER_ID)
references APP_USER (USER_ID);
alter table USER_ROLE
add constraint USER_ROLE_FK2 foreign key (ROLE_ID)
references APP_ROLE (ROLE_ID);
-- Used by Spring Remember Me API.
CREATE TABLE Persistent_Logins (
username varchar(64) not null,
series varchar(64) not null,
token varchar(64) not null,
last_used Datetime not null,
PRIMARY KEY (series)
);
--------------------------------------
insert into App_User (USER_ID, USER_NAME, ENCRYTED_PASSWORD, ENABLED)
values (2, 'dbuser1', '$2a$10$PrI5Gk9L.tSZiW9FXhTS8O8Mz9E97k2FZbFvGFFaSsiTUIl.TCrFu', 1);
insert into App_User (USER_ID, USER_NAME, ENCRYTED_PASSWORD, ENABLED)
values (1, 'dbadmin1', '$2a$10$PrI5Gk9L.tSZiW9FXhTS8O8Mz9E97k2FZbFvGFFaSsiTUIl.TCrFu', 1);
---
insert into app_role (ROLE_ID, ROLE_NAME)
values (1, 'ROLE_ADMIN');
insert into app_role (ROLE_ID, ROLE_NAME)
values (2, 'ROLE_USER');
---
insert into user_role (ID, USER_ID, ROLE_ID)
values (1, 1, 1);
insert into user_role (ID, USER_ID, ROLE_ID)
values (2, 1, 2);
insert into user_role (ID, USER_ID, ROLE_ID)
values (3, 2, 2);
ORACLE
-- Create table
create table APP_USER
(
USER_ID NUMBER(19) not null,
USER_NAME VARCHAR2(36) not null,
ENCRYTED_PASSWORD VARCHAR2(128) not null,
ENABLED NUMBER(1) not null
) ;
--
alter table APP_USER
add constraint APP_USER_PK primary key (USER_ID);
alter table APP_USER
add constraint APP_USER_UK unique (USER_NAME);
-- Create table
create table APP_ROLE
(
ROLE_ID NUMBER(19) not null,
ROLE_NAME VARCHAR2(30) not null
) ;
--
alter table APP_ROLE
add constraint APP_ROLE_PK primary key (ROLE_ID);
alter table APP_ROLE
add constraint APP_ROLE_UK unique (ROLE_NAME);
-- Create table
create table USER_ROLE
(
ID NUMBER(19) not null,
USER_ID NUMBER(19) not null,
ROLE_ID NUMBER(19) not null
);
--
alter table USER_ROLE
add constraint USER_ROLE_PK primary key (ID);
alter table USER_ROLE
add constraint USER_ROLE_UK unique (USER_ID, ROLE_ID);
alter table USER_ROLE
add constraint USER_ROLE_FK1 foreign key (USER_ID)
references APP_USER (USER_ID);
alter table USER_ROLE
add constraint USER_ROLE_FK2 foreign key (ROLE_ID)
references APP_ROLE (ROLE_ID);
-- Used by Spring Remember Me API.
CREATE TABLE Persistent_Logins (
username varchar2(64) not null,
series varchar2(64) not null,
token varchar2(64) not null,
last_used Date not null,
PRIMARY KEY (series)
);
--------------------------------------
insert into App_User (USER_ID, USER_NAME, ENCRYTED_PASSWORD, ENABLED)
values (2, 'dbuser1', '$2a$10$PrI5Gk9L.tSZiW9FXhTS8O8Mz9E97k2FZbFvGFFaSsiTUIl.TCrFu', 1);
insert into App_User (USER_ID, USER_NAME, ENCRYTED_PASSWORD, ENABLED)
values (1, 'dbadmin1', '$2a$10$PrI5Gk9L.tSZiW9FXhTS8O8Mz9E97k2FZbFvGFFaSsiTUIl.TCrFu', 1);
---
insert into app_role (ROLE_ID, ROLE_NAME)
values (1, 'ROLE_ADMIN');
insert into app_role (ROLE_ID, ROLE_NAME)
values (2, 'ROLE_USER');
---
insert into user_role (ID, USER_ID, ROLE_ID)
values (1, 1, 1);
insert into user_role (ID, USER_ID, ROLE_ID)
values (2, 1, 2);
insert into user_role (ID, USER_ID, ROLE_ID)
values (3, 2, 2);
---
Commit;
Postgres
-- Create table
create table APP_USER
(
USER_ID BIGINT not null,
USER_NAME VARCHAR(36) not null,
ENCRYTED_PASSWORD VARCHAR(128) not null,
ENABLED Int not null
) ;
--
alter table APP_USER
add constraint APP_USER_PK primary key (USER_ID);
alter table APP_USER
add constraint APP_USER_UK unique (USER_NAME);
-- Create table
create table APP_ROLE
(
ROLE_ID BIGINT not null,
ROLE_NAME VARCHAR(30) not null
) ;
--
alter table APP_ROLE
add constraint APP_ROLE_PK primary key (ROLE_ID);
alter table APP_ROLE
add constraint APP_ROLE_UK unique (ROLE_NAME);
-- Create table
create table USER_ROLE
(
ID BIGINT not null,
USER_ID BIGINT not null,
ROLE_ID BIGINT not null
);
--
alter table USER_ROLE
add constraint USER_ROLE_PK primary key (ID);
alter table USER_ROLE
add constraint USER_ROLE_UK unique (USER_ID, ROLE_ID);
alter table USER_ROLE
add constraint USER_ROLE_FK1 foreign key (USER_ID)
references APP_USER (USER_ID);
alter table USER_ROLE
add constraint USER_ROLE_FK2 foreign key (ROLE_ID)
references APP_ROLE (ROLE_ID);
-- Used by Spring Remember Me API.
CREATE TABLE Persistent_Logins (
username varchar(64) not null,
series varchar(64) not null,
token varchar(64) not null,
last_used timestamp not null,
PRIMARY KEY (series)
);
--------------------------------------
insert into App_User (USER_ID, USER_NAME, ENCRYTED_PASSWORD, ENABLED)
values (2, 'dbuser1', '$2a$10$PrI5Gk9L.tSZiW9FXhTS8O8Mz9E97k2FZbFvGFFaSsiTUIl.TCrFu', 1);
insert into App_User (USER_ID, USER_NAME, ENCRYTED_PASSWORD, ENABLED)
values (1, 'dbadmin1', '$2a$10$PrI5Gk9L.tSZiW9FXhTS8O8Mz9E97k2FZbFvGFFaSsiTUIl.TCrFu', 1);
---
insert into app_role (ROLE_ID, ROLE_NAME)
values (1, 'ROLE_ADMIN');
insert into app_role (ROLE_ID, ROLE_NAME)
values (2, 'ROLE_USER');
---
insert into user_role (ID, USER_ID, ROLE_ID)
values (1, 1, 1);
insert into user_role (ID, USER_ID, ROLE_ID)
values (2, 1, 2);
insert into user_role (ID, USER_ID, ROLE_ID)
values (3, 2, 2);
---
Commit;
3. Create Spring Boot Project
On the Eclipse, create aSpring Boot project.

Enter:
- Name: SbSecurityJdbcThymeleaf
- Group: org.o7planning
- Artifact: SbSecurityJdbcThymeleaf
- Description: Spring Boot + JDBC + Security + Thymeleaf
- Package: org.o7planning.sbsecurity

In the next step, you need to select the technologies and libraries to be used (In this lesson, we will connect to Oracle, MySQL, SQL Server or Postgres databases).
Database Libraries:
- MySQL
- PostgresSQL
- SQL Server
- Web
- Thymeleaf
- Security

OK, the Project has been created.

SbSecurityJdbcThymeleafApplication.java
package org.o7planning.sbsecurity;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SbSecurityJdbcThymeleafApplication {
public static void main(String[] args) {
SpringApplication.run(SbSecurityJdbcThymeleafApplication.class, args);
}
}
4. Configure pom.xml
If you use the Oracle database, you need to declare a necessary library to the Oracle in the pom.xml file:
** Oracle **
<dependencies>
.....
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc6</artifactId>
<version>11.2.0.3</version>
</dependency>
.....
</dependencies>
<repositories>
....
<!-- Repository for ORACLE JDBC Driver -->
<repository>
<id>codelds</id>
<url>https://code.lds.org/nexus/content/groups/main-repo</url>
</repository>
.....
</repositories>
If you connect to the SQL Service database, you can use eitherJTDS library or Mssql-Jdbc library:
** SQL Server **
<dependencies>
.....
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>net.sourceforge.jtds</groupId>
<artifactId>jtds</artifactId>
<scope>runtime</scope>
</dependency>
.....
</dependencies>
The full content of pom.xml file:
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>org.o7planning</groupId>
<artifactId>SbSecurityJdbcThymeleaf</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>SbSecurityJdbcThymeleaf</name>
<description>Spring Boot + JDBC + Security + Thymeleaf</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.0.RELEASE</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-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>net.sourceforge.jtds</groupId>
<artifactId>jtds</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc6</artifactId>
<version>11.2.0.3</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<repositories>
<!-- Repository for ORACLE JDBC Driver -->
<repository>
<id>codelds</id>
<url>https://code.lds.org/nexus/content/groups/main-repo</url>
</repository>
</repositories>
</project>
5. Configure Datasource
For Spring can be connected to Database, you need configure the necessary parameters in the application.properties file.

application.properties (ORACLE)
# Database Connection
spring.datasource.driver-class-name=oracle.jdbc.driver.OracleDriver
spring.datasource.url=jdbc:oracle:thin:@localhost:1521:db12c
spring.datasource.username=Test
spring.datasource.password=test001
# Other properties ..
application.properties (SQL Server + JTDS driver)
# Database Connection
spring.datasource.driver-class-name=net.sourceforge.jtds.jdbc.Driver
spring.datasource.url=jdbc:jtds:sqlserver://localhost:1433/simplehr;instance=SQLEXPRESS
spring.datasource.username=sa
spring.datasource.password=12345
# Other properties ..
application.properties (SQL Server + Mssql-jdbc Driver)
# Database Connection
spring.datasource.driver-class-name=com.microsoft.sqlserver.jdbc.SQLServerDriver
spring.datasource.url=jdbc:sqlserver://tran-vmware-pc\\SQLEXPRESS:1433;databaseName=Test
spring.datasource.username=sa
spring.datasource.password=12345
# Other properties ..
application.properties (MySQL)
# Database Connection
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/mydatabase
spring.datasource.username=root
spring.datasource.password=12345
# Other properties ..
application.properties (Postgres)
# Database Connection
spring.datasource.driver-class-name=org.postgresql.Driver
spring.datasource.url=jdbc:postgresql://localhost:5432/mydatabase
spring.datasource.username=postgres
spring.datasource.password=12345
# Other properties ..
6. Security configuration

This application has some functions (pages) of which:
- /userInfo
This is a page for viewing user's information. This page requires an user to log in and have the role such as ROLE_ADMIN or ROLE_USER.
- /admin
This is a page for administrator. It requires users to log in, and only the people with ROLE_ADMIN role has access.
- /. /welcome, /login, /logout, /403
All other pages of the application don't require users to log in.
The WebSecurityConfig class is used to configure security for the application. It is annotated by @Configuration. This annotation tells the Spring that it is a configuration class and therefore, it will be analyzed by the Sping at the time when the application runs.

WebSecurityConfig.java
package org.o7planning.sbsecurity.config;
import org.o7planning.sbsecurity.service.UserDetailsServiceImpl;
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;
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
UserDetailsServiceImpl userDetailsService;
@Bean
public BCryptPasswordEncoder passwordEncoder() {
BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
return bCryptPasswordEncoder;
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
// Setting Service to find User in the database.
// And Setting PassswordEncoder
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
// The pages does not require login
http.authorizeRequests().antMatchers("/", "/login", "/logout").permitAll();
// /userInfo page requires login as ROLE_USER or ROLE_ADMIN.
// If no login, it will redirect to /login page.
http.authorizeRequests().antMatchers("/userInfo").access("hasAnyRole('ROLE_USER', 'ROLE_ADMIN')");
// For ADMIN only.
http.authorizeRequests().antMatchers("/admin").access("hasRole('ROLE_ADMIN')");
// When the user has logged in as XX.
// But access a page that requires role YY,
// AccessDeniedException will be thrown.
http.authorizeRequests().and().exceptionHandling().accessDeniedPage("/403");
// Config for Login Form
http.authorizeRequests().and().formLogin()//
// Submit URL of login page.
.loginProcessingUrl("/j_spring_security_check") // Submit URL
.loginPage("/login")//
.defaultSuccessUrl("/userAccountInfo")//
.failureUrl("/login?error=true")//
.usernameParameter("username")//
.passwordParameter("password")
// Config for Logout Page
.and().logout().logoutUrl("/logout").logoutSuccessUrl("/logoutSuccessful");
}
}
7. Model, Mapper, DAO, WebUtils

The AppUser class represents for a record in the APP_USER table of database.
AppUser.java
package org.o7planning.sbsecurity.model;
public class AppUser {
private Long userId;
private String userName;
private String encrytedPassword;
public AppUser() {
}
public AppUser(Long userId, String userName, String encrytedPassword) {
this.userId = userId;
this.userName = userName;
this.encrytedPassword = encrytedPassword;
}
public Long getUserId() {
return userId;
}
public void setUserId(Long userId) {
this.userId = userId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getEncrytedPassword() {
return encrytedPassword;
}
public void setEncrytedPassword(String encrytedPassword) {
this.encrytedPassword = encrytedPassword;
}
@Override
public String toString() {
return this.userName + "/" + this.encrytedPassword;
}
}
The AppUserMapper class is used for mapping the columns in the APP_USER table with the fields in the AppUser class (Based on the query statement).
AppUserMapper.java
package org.o7planning.sbsecurity.mapper;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.o7planning.sbsecurity.model.AppUser;
import org.springframework.jdbc.core.RowMapper;
public class AppUserMapper implements RowMapper<AppUser> {
public static final String BASE_SQL //
= "Select u.User_Id, u.User_Name, u.Encryted_Password From App_User u ";
@Override
public AppUser mapRow(ResultSet rs, int rowNum) throws SQLException {
Long userId = rs.getLong("User_Id");
String userName = rs.getString("User_Name");
String encrytedPassword = rs.getString("Encryted_Password");
return new AppUser(userId, userName, encrytedPassword);
}
}
DAO (Data Access Object) classes are ones used to access to a database, for example, Query, Insert, Update, Delete. The DAO classes are usually annotated by @Repository to tell the Spring "let's manage them as Spring BEANs".
The AppUserDAO class is used to manipulate with the APP_USER table. It has a method for finding an user in the database corresponding to an username.
AppUserDAO.java
package org.o7planning.sbsecurity.dao;
import javax.sql.DataSource;
import org.o7planning.sbsecurity.mapper.AppUserMapper;
import org.o7planning.sbsecurity.model.AppUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.support.JdbcDaoSupport;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
@Repository
@Transactional
public class AppUserDAO extends JdbcDaoSupport {
@Autowired
public AppUserDAO(DataSource dataSource) {
this.setDataSource(dataSource);
}
public AppUser findUserAccount(String userName) {
// Select .. from App_User u Where u.User_Name = ?
String sql = AppUserMapper.BASE_SQL + " where u.User_Name = ? ";
Object[] params = new Object[] { userName };
AppUserMapper mapper = new AppUserMapper();
try {
AppUser userInfo = this.getJdbcTemplate().queryForObject(sql, params, mapper);
return userInfo;
} catch (EmptyResultDataAccessException e) {
return null;
}
}
}
AppRoleDAO.java
package org.o7planning.sbsecurity.dao;
import java.util.List;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.support.JdbcDaoSupport;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
@Repository
@Transactional
public class AppRoleDAO extends JdbcDaoSupport {
@Autowired
public AppRoleDAO(DataSource dataSource) {
this.setDataSource(dataSource);
}
public List<String> getRoleNames(Long userId) {
String sql = "Select r.Role_Name " //
+ " from User_Role ur, App_Role r " //
+ " where ur.Role_Id = r.Role_Id and ur.User_Id = ? ";
Object[] params = new Object[] { userId };
List<String> roles = this.getJdbcTemplate().queryForList(sql, params, String.class);
return roles;
}
}
-
WebUtils.java
package org.o7planning.sbsecurity.utils;
import java.util.Collection;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;
public class WebUtils {
public static String toString(User user) {
StringBuilder sb = new StringBuilder();
sb.append("UserName:").append(user.getUsername());
Collection<GrantedAuthority> authorities = user.getAuthorities();
if (authorities != null && !authorities.isEmpty()) {
sb.append(" (");
boolean first = true;
for (GrantedAuthority a : authorities) {
if (first) {
sb.append(a.getAuthority());
first = false;
} else {
sb.append(", ").append(a.getAuthority());
}
}
sb.append(")");
}
return sb.toString();
}
}
EncrytedPasswordUtils.java
package org.o7planning.sbsecurity.utils;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
public class EncrytedPasswordUtils {
// Encryte Password with BCryptPasswordEncoder
public static String encrytePassword(String password) {
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
return encoder.encode(password);
}
public static void main(String[] args) {
String password = "123";
String encrytedPassword = encrytePassword(password);
System.out.println("Encryted Password: " + encrytedPassword);
}
}
8. UserDetailsService
UserDetailsService means a central interface in Spring Security. It is a service to search "User account and such user's roles". It is used by the Spring Security everytime when users log in the system. Therefore, you need to write a class to implement this interface.
Herein, I create the UserDetailsServiceImpl class which implements the UserDetailsService interface. The UserDetailsServiceImpl class is annotated by@Service to tell the Spring "let's manage it as a Spring BEAN".
UserDetailsServiceImpl.java
package org.o7planning.sbsecurity.service;
import java.util.ArrayList;
import java.util.List;
import org.o7planning.sbsecurity.dao.AppUserDAO;
import org.o7planning.sbsecurity.dao.AppRoleDAO;
import org.o7planning.sbsecurity.model.AppUser;
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;
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
@Autowired
private AppUserDAO appUserDAO;
@Autowired
private AppRoleDAO appRoleDAO;
@Override
public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
AppUser appUser = this.appUserDAO.findUserAccount(userName);
if (appUser == null) {
System.out.println("User not found! " + userName);
throw new UsernameNotFoundException("User " + userName + " was not found in the database");
}
System.out.println("Found User: " + appUser);
// [ROLE_USER, ROLE_ADMIN,..]
List<String> roleNames = this.appRoleDAO.getRoleNames(appUser.getUserId());
List<GrantedAuthority> grantList = new ArrayList<GrantedAuthority>();
if (roleNames != null) {
for (String role : roleNames) {
// ROLE_USER, ROLE_ADMIN,..
GrantedAuthority authority = new SimpleGrantedAuthority(role);
grantList.add(authority);
}
}
UserDetails userDetails = (UserDetails) new User(appUser.getUserName(), //
appUser.getEncrytedPassword(), grantList);
return userDetails;
}
}
9. Controllers
MainController.java
package org.o7planning.sbsecurity.controller;
import java.security.Principal;
import org.o7planning.sbsecurity.utils.WebUtils;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@Controller
public class MainController {
@RequestMapping(value = { "/", "/welcome" }, method = RequestMethod.GET)
public String welcomePage(Model model) {
model.addAttribute("title", "Welcome");
model.addAttribute("message", "This is welcome page!");
return "welcomePage";
}
@RequestMapping(value = "/admin", method = RequestMethod.GET)
public String adminPage(Model model, Principal principal) {
User loginedUser = (User) ((Authentication) principal).getPrincipal();
String userInfo = WebUtils.toString(loginedUser);
model.addAttribute("userInfo", userInfo);
return "adminPage";
}
@RequestMapping(value = "/login", method = RequestMethod.GET)
public String loginPage(Model model) {
return "loginPage";
}
@RequestMapping(value = "/logoutSuccessful", method = RequestMethod.GET)
public String logoutSuccessfulPage(Model model) {
model.addAttribute("title", "Logout");
return "logoutSuccessfulPage";
}
@RequestMapping(value = "/userInfo", method = RequestMethod.GET)
public String userInfo(Model model, Principal principal) {
// (1) (en)
// After user login successfully.
// (vi)
// Sau khi user login thanh cong se co principal
String userName = principal.getName();
System.out.println("User Name: " + userName);
User loginedUser = (User) ((Authentication) principal).getPrincipal();
String userInfo = WebUtils.toString(loginedUser);
model.addAttribute("userInfo", userInfo);
return "userInfoPage";
}
@RequestMapping(value = "/403", method = RequestMethod.GET)
public String accessDenied(Model model, Principal principal) {
if (principal != null) {
User loginedUser = (User) ((Authentication) principal).getPrincipal();
String userInfo = WebUtils.toString(loginedUser);
model.addAttribute("userInfo", userInfo);
String message = "Hi " + principal.getName() //
+ "<br> You do not have permission to access this page!";
model.addAttribute("message", message);
}
return "403Page";
}
}
10. Thymeleaf Template

The _menu.html is used as part of website. It is immersed into other sites to create the Menu of site.
_menu.html
<div xmlns:th="http://www.thymeleaf.org"
style="border: 1px solid #ccc;padding:5px;margin-bottom:20px;">
<a th:href="@{/}">Home</a>
|
<a th:href="@{/userInfo}">User Info</a>
|
<a th:href="@{/admin}">Admin</a>
|
<a th:if="${#request.userPrincipal != null}" th:href="@{/logout}">Logout</a>
</div>
welcomePage.html
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title th:utext="${title}"></title>
</head>
<body>
<!-- Include _menu.html -->
<th:block th:include="/_menu"></th:block>
<h2>Message : <span th:utext="${message}"></span></h2>
</body>
</html>
loginPage.html
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Login</title>
</head>
<body>
<!-- Include _menu.html -->
<th:block th:include="/_menu"></th:block>
<h1>Login</h1>
<!-- /login?error=true -->
<div th:if="${#request.getParameter('error') == 'true'}"
style="color:red;margin:10px 0px;">
Login Failed!!!<br />
Reason :
<span th:if="${#session!= null and #session.getAttribute('SPRING_SECURITY_LAST_EXCEPTION') != null}"
th:utext="${#session.getAttribute('SPRING_SECURITY_LAST_EXCEPTION').message}">
Static summary
</span>
</div>
<h3>Enter user name and password:</h3>
<form name='f' th:action="@{/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><input name="submit" type="submit" value="submit" /></td>
</tr>
</table>
</form>
<br>
Username/pass:
<ul>
<li>dbuser1/123</li>
<li>dbadmin1/123</li>
</ul>
</body>
</html>
logoutSuccessfulPage.html
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Logout</title>
</head>
<body>
<!-- Include _menu.html -->
<th:block th:include="/_menu"></th:block>
<h1>Logout Successful!</h1>
</body>
</html>
userInfoPage.html
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>User Info</title>
</head>
<body>
<!-- Include _menu.html -->
<th:block th:include="/_menu"></th:block>
<h2>User Info Page</h2>
<h3>Welcome : <span th:utext="${#request.userPrincipal.name}"></span></h3>
<b>This is protected page!</b>
<br/><br/>
<div th:if="${userInfo != null}" th:utext="${userInfo}"></div>
</body>
</html>
adminPage.html
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title th:utext="${title}"></title>
</head>
<body>
<!-- Include _menu.html -->
<th:block th:include="/_menu"></th:block>
<h2>Admin Page</h2>
<h3>Welcome :
<span th:utext="${#request.userPrincipal.name}"></span>
</h3>
<b>This is protected page!</b>
<br/><br/>
<div th:if="${userInfo != null}" th:utext="${userInfo}"></div>
</body>
</html>
If users log in the system, but access a unauthorized site (not their role), the system will display the content of the /403 page to inform that the access is denied.
403Page.html
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Access Denied</title>
</head>
<body>
<!-- Include _menu.html -->
<th:block th:include="/_menu"></th:block>
<h3 th:if="${message != null}" th:utext="${message}" style="color: red;"></h3>
<div th:if="${userInfo != null}" th:utext="${userInfo}"></div>
</body>
</html>
Spring Boot Tutorials
- Install Spring Tool Suite for Eclipse
- Spring Tutorial for Beginners
- Spring Boot Tutorial for Beginners
- Spring Boot Common Properties
- Spring Boot and Thymeleaf Tutorial with Examples
- Spring Boot and FreeMarker Tutorial with Examples
- Spring Boot and Groovy Tutorial with Examples
- Spring Boot and Mustache Tutorial with Examples
- Spring Boot and JSP Tutorial with Examples
- Spring Boot, Apache Tiles, JSP Tutorial with Examples
- Use Logging in Spring Boot
- Application Monitoring with Spring Boot Actuator
- Create a Multi Language web application with Spring Boot
- Use multiple ViewResolvers in Spring Boot
- Use Twitter Bootstrap in Spring Boot
- Spring Boot Interceptors Tutorial with Examples
- Spring Boot, Spring JDBC and Spring Transaction Tutorial with Examples
- Spring JDBC Tutorial with Examples
- Spring Boot, JPA and Spring Transaction Tutorial with Examples
- Spring Boot and Spring Data JPA Tutorial with Examples
- Spring Boot, Hibernate and Spring Transaction Tutorial with Examples
- Integrating Spring Boot, JPA and H2 Database
- Spring Boot and MongoDB Tutorial with Examples
- Use Multiple DataSources with Spring Boot and JPA
- Use Multiple DataSources with Spring Boot and RoutingDataSource
- Create a Login Application with Spring Boot, Spring Security, Spring JDBC
- Create a Login Application with Spring Boot, Spring Security, JPA
- Create a User Registration Application with Spring Boot, Spring Form Validation
- Example of OAuth2 Social Login in Spring Boot
- Run background scheduled tasks in Spring
- CRUD Restful Web Service Example with Spring Boot
- Spring Boot Restful Client with RestTemplate Example
- CRUD Example with Spring Boot, REST and AngularJS
- Secure Spring Boot RESTful Service using Basic Authentication
- Secure Spring Boot RESTful Service using Auth0 JWT
- Spring Boot File Upload Example
- Spring Boot File Download Example
- Spring Boot File Upload with jQuery Ajax Example
- Spring Boot File Upload with AngularJS Example
- Create a Shopping Cart Web Application with Spring Boot, Hibernate
- Spring Email Tutorial with Examples
- Create a simple Chat application with Spring Boot and Websocket
- Deploy Spring Boot Application on Tomcat Server
- Deploy Spring Boot Application on Oracle WebLogic Server
- Install a free Let's Encrypt SSL certificate for Spring Boot
- Configure Spring Boot to redirect HTTP to HTTPS
- Fetch data with Spring Data JPA DTO Projections
Show More