Spring Security Default login page with JPA

Spring Boot Security Default Login Page with JPA Tutorial | Form Login & BCrypt

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

Spring Boot Security with JPA project structure showing config, controller, model, repository, and service packages
Figure 1: Spring Boot Security with JPA 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

Spring Boot Security default login page displayed in browser
Figure 2: Default Spring Security login page
Registering a new user via POST request to /register endpoint
Figure 3: User registration via /register endpoint
Spring Security login page with username and password fields filled in
Figure 4: Login form with credentials
Successful login redirect to the protected home page
Figure 5: Successful login — protected home page
Logout confirmation page after clicking logout
Figure 6: Logout confirmation

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 /register endpoint that hashes passwords with BCrypt.
  • CustomLoginDetailService — loads users from the database by username.
  • CustomLoginDetail — adapts the Login entity to Spring Security's UserDetails contract.
  • LoginRepository — Spring Data JPA repository with a custom getLoginByUsername method.
  • Login entity — JPA entity mapped to the login table.

Key takeaways:

  • Spring Boot auto-configures the default login page when spring-boot-starter-security is 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: