Kudos 👏 to reach till here.
In the previous article, we were implementing in-memory authentication in Spring security. But what if we need to connect to a datasource instead of an in-memory.
In this article, we’ll fo throught JDBC authentication.
Most of the concept is same as before, the only difference is setting up a jdbc authentication in the configure method.
Below is the code —
@EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure (AuthenticationManagerBuilder auth) { auth.jdbcAuthentication(); } @Override protected void configure (HttpSecurity http) { http.authorizeRequests() .antMatchers("/admin").hasRole("ADMIN"). .antMatchers("/user").hasAnyRole("ADMIN","USER"). .antMatchers("/**").permitAll(). .hasAnyRole(); } }
Now, we need to setup our authentication to tell Spring Security to lookup the user and password in the database. To do so, we need a bean for data source. By default, Spring security provides DataSource class which we can autowire in our project.
@Autowired DataSource datasource; @Override protected void configure (AuthenticationManagerBuilder auth) { auth.jdbcAuthentication() .dataSource(dataSource); }
But how does the spring knows the configuration of the data source.
We must configure it somewhere or else if we’re using H2 which is in-memory database, then spring by default creates a datasource.
For now, lets assume we have H2 in our class path.
@Autowired DataSource datasource; @Override protected void configure (AuthenticationManagerBuilder auth) { auth.jdbcAuthentication() .dataSource(dataSource); .dataSource(dataSource) .withDefaultSchema() .withUser( user.withUserName("user") .password("pass") .roles("USER") .withUserName("admin") .password("pass") .roles("ADMIN") ); }
In the above code, we’re using a default schema and creating the users.
When a client sends a request along with a password, the authentication configuration creates these 2 users and checks do the user in request matches to these. Hence authenticating the request.
Now, what if we already have a schema or we don’t want to use the default schema and you don’t want to put user creation logic in the code?
Create your own schema in resources -> schema.sql
schema.sql :
create table users( username varchar_ignorecase(50) not null primary key, password varchar_ignorecase(50) not null, enabled boolean not null ); create table authorities ( username varchar_ignorecase(50) not null, authority varchar_ignorecase(50) not null, constraint fk_authorities_users foreign key(username) references users(username) ); create unique index ix_auth_username on authorities (username,authority);
data.sql :
INSERT INTO users (username, password, enabled) VALUES ('user', 'pass', true), ('admin', 'pass', true); INSERT INTO authorities (username, authority) VALUES ('user', 'ROLE_USER'), ('admin', 'ROLE_ADMIN'); Important notes:
The password should ideally be encoded (BCrypt is recommended) rather than stored in plain text like this
Spring Security expects the authorities/roles to be prefixed with “ROLE_” by default
The enabled column must be set to true for the users to be able to authenticate
Below is the complete code for configuration class:
@EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired DataSource dataSource; @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.jdbcAuthentication() .dataSource(dataSource) .passwordEncoder(passwordEncoder()); } @Override protected void configure (HttpSecurity http) { http.authorizeRequests() .antMatchers("/admin").hasRole("ADMIN"). .antMatchers("/user").hasAnyRole("ADMIN","USER"). .antMatchers("/**").permitAll(). .hasAnyRole(); } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } }
When you autowire DataSource and use it in auth.jdbcAuthentication(), Spring Security automatically uses this DataSource to query the database for user authentication.
By default, it looks for tables: users (with username, password, enabled columns) , authorities (with username, authority columns)
If your schema is different, you can customize the queries.
auth.jdbcAuthentication() .dataSource(dataSource) .usersByUsernameQuery("Select username, password, enables" + "from custom_users where username = ?") .authoritiesByUsernameQuery("Select username, authority " + "from authorities where username = ?");
If you’re using MySQL, you need to define the DataSource in application.properties:
spring.datasource.url=jdbc:mysql://localhost:3306/spring_security_db spring.datasource.username=root spring.datasource.password=password spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
Great 👏
You’ve now got a good idea about spring security and jdbc authentication.
Next, let’s dive deep into JWT and implementing it using Spring security.
Thanks for reading.
Top comments (0)