Till now, we are using the in-memory data for studying purpose.
DemoSecurityConfig.java:1
2
3
4
5
6
7
8
9
10
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// add our users for in memory authentication
UserBuilder users = User.withDefaultPasswordEncoder();
auth.inMemoryAuthentication()
.withUser(users.username("john").password("test123").roles("EMPLOYEE"))
.withUser(users.username("mary").password("test123").roles("EMPLOYEE","MANAGER"))
.withUser(users.username("susan").password("test123").roles("EMPLOYEE","ADMIN"));
}
And now, we will try to add database access.
Database Support in Spring Security
- Spring Security can read user account info from database
- By default, you have to follow Spring Security’s predefined table schemas
Development Process
Develop SQL Script to set up databse tables
Spring Security has a default database schema, so you need to provide two tables, one callusers
and one callauthorities
. And you have to use these exact table names, and also these tables need to have these columns: username, password and enabled for users, and authorities is the username and authority(authority is the same thing as roles).1
2
3
4
5
6
7CREATE TABLE `users` (
`username` varchar(50) NOT NULL,
`password` varchar(50) NOT NULL,
`enabled` tinyint(1) NOT NULL,
PRIMARY KEY (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;In Spring Security 5, passwords are stored using a specific format:
{id}encodedPassword
| id | Description |
| —— | —— |
| noop | Plain text passwords |
| bcrypt | BCrypt password hashing |1
2
3
4
5INSERT INTO `users`
VALUES
('john','{noop}test123',1),
('mary','{noop}test123',1),
('susan','{noop}test123',1);Note: the password is “test123” while the {noop} let Spring Security know the passwords are stored as plain text{noop}
1
2
3
4
5
6
7
8
9
10CREATE TABLE `authorities` (
`username` varchar(50) NOT NULL,
`authority` varchar(50) NOT NULL,
UNIQUE KEY `authorities_idx_1` (`username`,`authority`),
CONSTRAINT `authorities_ibfk_1`
FOREIGN KEY (`username`)
REFERENCES `users`(`username`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;1
2
3
4
5
6
7INSERT INTO `authorities`
VALUES
('john','ROLE_EMPLOYEE'),
('mary','ROLE_EMPLOYEE'),
('mary','ROLE_MANAGER'),
('susan','ROLE_EMPLOYEE'),
('susan','ROLE_ADMIN');Note: Internally Spring Security uses “ROLE_” prefix
Add database support to Maven POM file
pom.xml:1
2
3
4
5
6
7
8
9
10
11<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.45</version>
</dependency>
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.2</version>
</dependency>Create JDBC properties file
src/main/resources/persistence-mysql.properties:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15#
# JDBC connection properties
#
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/spring_security_demo_plaintext?useSSL=false
jdbc.user=root
jdbc.password=pwd
#
# Connection poll properties
#
connection.pool.initialPoolSize=5
connection.pool.minPoolSize=5
connection.pool.maxPoolSize=20
connection.pool.maxIdleTime=3000Define DataSource in Spring Configuration
DemoAppConfig.java:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
"com.xliu.springsecurity.demo") (basePackages =
// src/main/resources files are automatically copied to classpath during Mavan build
"classpath:persistence-mysql.properties") (
public class DemoAppConfig {
private Environment env;
private Logger logger = Logger.getLogger(getClass().getName());
public DataSource securityDataSource() {
// create connection poll
ComboPooledDataSource securityDataSource = new ComboPooledDataSource();
// set the jdbc driver
try {
securityDataSource.setDriverClass(env.getProperty("jdbc.driver"));
} catch (PropertyVetoException e) {
throw new RuntimeException(e);
}
logger.info(">>>> jdbc.url=" + env.getProperty("jdbc.url"));
logger.info(">>>> jdbc.user=" + env.getProperty("jdbc.user"));
// set database connection props
securityDataSource.setJdbcUrl(env.getProperty("jdbc.url"));
securityDataSource.setUser(env.getProperty("jdbc.user"));
securityDataSource.setPassword(env.getProperty("jdbc.password"));
// set connection pool props
securityDataSource.setInitialPoolSize(Integer.parseInt(env.getProperty("connection.pool.initialPoolSize")));
securityDataSource.setMinPoolSize(Integer.parseInt(env.getProperty("connection.pool.minPoolSize")));
securityDataSource.setMaxPoolSize(Integer.parseInt(env.getProperty("connection.pool.maxPoolSize")));
securityDataSource.setMaxIdleTime(Integer.parseInt(env.getProperty("connection.pool.maxIdleTime")));
return securityDataSource;
}Environment is a Spring helper class to hold the data that was read from the properties file
- Update Spring Security Configuration to use JDBC
DemoSecurityConfig.java:1
2
3
4
5
6
7
8
9
10
public class DemoSecurityConfig extends WebSecurityConfigurerAdapter {
// Inject our data source that we just configured
private DataSource securityDataSource;
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// Tell Spring Security to use JDBC authentication with our data source
auth.jdbcAuthentication().dataSource(securityDataSource);
Here we no longer use hard-coding users.