Spring Boot Security Default Login Page with JPA Tutorial
Author: Deep Singh | Category: Java, Spring Boot, Spring Security, JPA
Introduction
In this tutorial, you'll learn how to secure a Spring Boot application using the default Spring Security login page backed by JPA and MySQL. We'll implement a custom UserDetailsService, use BCrypt for password hashing, and register users through a REST endpoint.
By the end, you'll have:
- A working form-based login using Spring Security's default login page
- User credentials stored in a MySQL database via JPA
- BCrypt password encoding
- A protected
/endpoint accessible only after login
Project Structure
LoginController.java
This REST controller exposes a protected / endpoint and a public /register endpoint for user registration. The password is encoded using BCryptPasswordEncoder before saving.
package com.deepsingh44.login.jpa.controller;
import com.deepsingh44.login.jpa.model.Login;
import com.deepsingh44.login.jpa.repository.LoginRepository;
import com.deepsingh44.login.jpa.service.CustomLoginDetailService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.web.bind.annotation.*;
@RestController
public class LoginController {
@Autowired
private LoginRepository loginRepository;
@Autowired
private CustomLoginDetailService customLoginDetailService;
@Autowired
private BCryptPasswordEncoder bCryptPasswordEncoder;
@GetMapping("/")
public String home() {
return "Welcome to Secure web page";
}
@PostMapping("/register")
public Login register(@RequestBody Login login) {
String encodepassword = bCryptPasswordEncoder.encode(login.getPassword());
login.setPassword(encodepassword);
return loginRepository.save(login);
}
}
SecurityConfig.java
This configuration class enables web security, disables CSRF, permits access to /register, requires authentication for all other requests, and enables the default form-based login and logout.
package com.deepsingh44.login.jpa.config;
import com.deepsingh44.login.jpa.service.CustomLoginDetailService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
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;
@EnableWebSecurity
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private CustomLoginDetailService customLoginDetailService;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(customLoginDetailService)
.passwordEncoder(passwordEncoder());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/register").permitAll()
.anyRequest().authenticated()
.and()
.formLogin().permitAll()
.and()
.logout().permitAll();
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
CustomLoginDetail.java
A custom implementation of Spring Security's UserDetails interface that wraps our Login entity and exposes its username and password.
package com.deepsingh44.login.jpa.model;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.Collection;
@Component
public class CustomLoginDetail implements UserDetails {
private Login login;
public CustomLoginDetail(Login login) {
this.login = login;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return new ArrayList();
}
@Override
public String getPassword() {
return login.getPassword();
}
@Override
public String getUsername() {
return login.getUsername();
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
}
Login.java
The JPA entity representing the user credentials stored in the login table.
package com.deepsingh44.login.jpa.model;
import org.springframework.stereotype.Component;
import javax.persistence.*;
@Component
@Entity
@Table(name = "login")
public class Login {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int id;
private String username;
private String password;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
LoginRepository.java
Spring Data JPA repository providing CRUD operations and a custom getLoginByUsername method.
package com.deepsingh44.login.jpa.repository;
import com.deepsingh44.login.jpa.model.Login;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface LoginRepository extends JpaRepository<Login, Integer> {
Login getLoginByUsername(String username);
}
CustomLoginDetailService.java
Implements UserDetailsService to load a user from the database by username and wrap it in a CustomLoginDetail object.
package com.deepsingh44.login.jpa.service;
import com.deepsingh44.login.jpa.model.CustomLoginDetail;
import com.deepsingh44.login.jpa.model.Login;
import com.deepsingh44.login.jpa.repository.LoginRepository;
import org.springframework.beans.factory.annotation.Autowired;
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 CustomLoginDetailService implements UserDetailsService {
@Autowired
private LoginRepository loginRepository;
@Override
public UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException {
Login login = loginRepository.getLoginByUsername(username);
if (login == null) {
throw new UsernameNotFoundException("Could not find login user");
}
return new CustomLoginDetail(login);
}
}
DefaultLoginJpaApplication.java
The main Spring Boot application entry point.
package com.deepsingh44.login.jpa;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DefaultLoginJpaApplication {
public static void main(String[] args) {
SpringApplication.run(DefaultLoginJpaApplication.class, args);
}
}
application.properties
Configure the MySQL datasource and JPA/Hibernate properties.
spring.datasource.url=jdbc:mysql://localhost:3306/mystudents
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
server.port=8081
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
spring.jpa.hibernate.ddl-auto=update
pom.xml
Required Maven dependencies for Spring Boot, Spring Security, Spring Data JPA, and MySQL.
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</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-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.37</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>
Output Screens
Conclusion
In this tutorial, we implemented a complete Spring Boot Security setup using the default login page backed by JPA and MySQL. We covered the full authentication flow:
- SecurityConfig — enables web security, disables CSRF, permits
/register, and enables the default form login and logout. - LoginController — exposes a protected
/endpoint and a public/registerendpoint that hashes passwords with BCrypt. - CustomLoginDetailService — loads users from the database by username.
- CustomLoginDetail — adapts the
Loginentity to Spring Security'sUserDetailscontract. - LoginRepository — Spring Data JPA repository with a custom
getLoginByUsernamemethod. - Login entity — JPA entity mapped to the
logintable.
Key takeaways:
- Spring Boot auto-configures the default login page when
spring-boot-starter-securityis on the classpath. - BCryptPasswordEncoder securely hashes passwords before storage.
- UserDetailsService is the extension point for loading users from any source (JPA, LDAP, etc.).
- CSRF must be disabled for stateless REST APIs (or configured properly for browser-based apps).
You can extend this example by adding role-based access control, a custom login page, remember-me functionality, account locking, or OAuth2 integration. This foundational setup is the starting point for nearly every secured Spring Boot web application.
No comments:
Post a Comment