Spring Boot Security – Form Based Authentication – Persistence Token – Remember Me

Remember Me Authentication – Persistence Token

The example Spring Boot Security form based authentication persistence token remember me 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 remember me – persistent token – on Spring MVC framework. The similar example I will implement here but using Spring Boot framework. I will add additional field checkbox as remember me into the login form.

This tutorial will show you how to remember your credentials for a specific time period for auto-login without providing any login credentials into the login form.

Remember-me or persistent-login authentication refers to web sites being able to remember the identity of a principal between sessions.

This is typically accomplished by sending a cookie to the browser, with the cookie being detected during future sessions and causing automated login to take place.

Spring Security provides the necessary hooks for these operations to take place, and has two concrete remember-me implementations. One uses hashing to preserve the security of cookie-based tokens and the other uses a database or other persistent storage mechanism to store the generated tokens.

This example uses database storage to store generated tokens for Remember Me login implementation as opposed to the tutorial, where cookie based token approach was achieved.

I will use here JDBC authentication, you can check my other Spring Security tutorials.

Prerequisites

Java 1.8/19, Gradle 5.4.1, Spring Boot 2.1.6/3.1.4, Maven 3.8.5, MySQL 8.1.0

Read tutorial Spring Boot Security Form based JDBC Authentication before proceeding below sections.

Adding SQL Script

For spring boot 3.x.x application I am not going to use in-memory database and I will use MySQL database.

I am not going to tell you from the initial project creation but I will modify the existing application as I asked you to read tutorial before coming here.

You may also download the complete source code later from this tutorial.

I need to add a SQL script to create a table for storing the token into database.

Create a file called persistent_logins.sql in addition to other SQL scripts under src/main/resources folder with the following content.

DROP TABLE IF EXISTS `persistent_logins`;
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`)
);

Database Config Class

The database configuration class is not required for spring boot 3.x.x version app for this example.

Need to define additional bean for persistence token approach. The token will be saved into database and will be checked for authentication for remember me option.

@Bean
public PersistentTokenRepository persistentTokenRepository() {
	JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl();
	tokenRepository.setDataSource(dataSource());
	return tokenRepository;
}

The complete source code for DatabaseConfig.java file is given below:

@Configuration
public class DatabaseConfig {
	@Bean
	public DataSource dataSource() {
		EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
		EmbeddedDatabase db = builder.setType(EmbeddedDatabaseType.H2) // .H2 or .DERBY, etc.
				.addScript("user.sql").addScript("user-role.sql").addScript("persistent_logins.sql").build();
		return db;
	}
	@Bean
	public PersistentTokenRepository persistentTokenRepository() {
		JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl();
		tokenRepository.setDataSource(dataSource());
		return tokenRepository;
	}
}

Security Config Class

The following spring security configuration is for the spring boot 3.x.x version.

@Configuration
public class SecurityConfig {

	@Autowired
	private DataSource dataSource;

	@Autowired
	private PasswordEncoder passwordEncoder;

	@Autowired
	private UserAuthService userAuthService;

	@Bean
	public PersistentTokenRepository persistentTokenRepository() {
		JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl();
		tokenRepository.setDataSource(dataSource);
		return tokenRepository;
	}

	@Autowired
	public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
		auth.userDetailsService(userAuthService).passwordEncoder(passwordEncoder);
	}

	@Bean
	public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
		http.authorizeHttpRequests(auth -> auth
				// ignore home, login, error pages and css files
				.requestMatchers("/", "/login", "/css/**", "/error**").permitAll().requestMatchers("/admin")
				.hasRole("ADMIN").anyRequest().authenticated()); // check for admin url with ADMIN role
		// allow users to authenticate with form based login
		http.formLogin(form -> form.loginPage("/login") // specifies custom login page
				.permitAll().usernameParameter("username") // overrides spring's default j_username with username
															// parameter
				.passwordParameter("password") // overrides spring's default j_password with password parameter
				.loginProcessingUrl("/j_spring_security_check") // login processing url
				.defaultSuccessUrl("/admin") // default target url which will be shown after successful login
				.failureUrl("/login?error")); // authenticate failure url
		http.logout((logout) -> logout.permitAll()); // logout
		http.rememberMe(remember -> remember.rememberMeServices(rememberMeServices())); // remember me
		return http.build();
	}

	@Bean
	RememberMeServices rememberMeServices() {
		PersistentTokenBasedRememberMeServices rememberMe = new PersistentTokenBasedRememberMeServices("rememberKey",
				userAuthService, persistentTokenRepository());
		rememberMe.setParameter("remember"); // remember me field name in login form
		rememberMe.setTokenValiditySeconds(86400); // remember me for one day
		return rememberMe;
	}

}

The following spring security configuration is for the spring boot 2.x.x version.

The file is quite self-explanation and I have added the following code snippets in addition to the existing code base.

.and().rememberMe()// remember me,
				.key("rememberKey")// key for remember me,
				.rememberMeParameter("remember")// remember me field name in login form,
				.tokenValiditySeconds(86400);// remember me for one day

The updated SecurityConfig.java file is shown below:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
	@Autowired
	private DataSource dataSource;
	@Autowired
	public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
		final String sqlUserName = "select u.user_name, u.user_pass, u.enable from user u where u.user_name = ?";
		final String sqlAuthorities = "select ur.user_name, ur.user_role from user_role ur where ur.user_name = ?";
		auth.jdbcAuthentication().dataSource(dataSource).usersByUsernameQuery(sqlUserName)
				.authoritiesByUsernameQuery(sqlAuthorities).passwordEncoder(passwordEncoder());
	}
	@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,
				.and().rememberMe()// remember me,
				.key("rememberKey")// key for remember me,
				.rememberMeParameter("remember")// remember me field name in login form,
				.tokenValiditySeconds(86400);// remember me for one day
	}
	@Bean
	public PasswordEncoder passwordEncoder() {
		return new BCryptPasswordEncoder();
	}
}

The above configuration is persistent token approach and this approach is more robust as opposed to simple hash based token approach, which is exposed to a security threat, because a captured remember-me token will be usable from any user agent until such time as the token expires and is usually not recommended.

Login Form

For spring boot 3.x.x version I am going to use Thymeleaf framework for HTML pages. The HTML pages and CSS file will be kept under src/main/resources folder. The HTML pages are kept under templates sub-folder and CSS file is kept under static/css sub-folder.

I will use the existing login.jsp page and update the login form to include additional checkbox for remember me option.

The following code snippets have been added to the login form.

<tr>
	<td>Remember Me:</td>
	<td><input type='checkbox' name="remember" /></td>
</tr>

I have provided an option, usually checkbox, to the user to select Remember Me and if a user checks it then after successful login, spring application sends a remember-me cookie to the browser in addition to session cookie. Once the session cookie is expired, then if user accesses the secure page, it will automatically be logged-in using remember-me cookie.

Deploying and Testing Persistence Token Application

Deploying and testing application is same as Spring Boot Security Form based JDBC Authentication.

Now when you try to access the admin page you will be redirected to login page and you will see the Remember Mecheckbox for next time auto-login.

spring boot security form based authentication persistence token remember me

So once you login with checkbox checked and next time when you hit the direct URL http://localhost:8080/admin into the browser you will automatically be redirected to the admin page and you are no longer required to login using credentials.

Or even if you click on the link Go to Administrator page from home page, you will be automatically redirected to the admin page.

You will also find entry into the database table with token value.

persistence token

Source Code

Download

Leave a Reply

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