Spring Security Customise Login and Logout in Spring Boot Example

In this example, we will learn how to customise Spring Security in Login and Logout in Spring Boot example. Spring Security provides a default login form and logout feature. We will create a step-by-step Spring Boot application with Spring Security to customize a login and logout feature.

Table of content

1. Keep Eclipse IDE ready(STS integrated)
2. Create a Spring Boot Starter Project 
3. Maven Dependency
4. Create a view page
5. Create a Controller class
6. Create a Spring Security Config class
7. Run the Application
8. How to use different field names and URL in Login in Spring Security?
9. Login Success Handler
10. Logout Success Handler
11. Conclusion

1. Keep Eclipse IDE ready(STS integrated)

Refer to this article How to Create Spring Project in IDE to create Spring Boot Project in Eclipse IDE.

2. Create a Spring Boot Starter Project 

Add the following dependencies: 
• Spring Web 
• Spring Security
• Thymeleaf

Project Structure of Spring Security in Login and Logout in Spring Boot

spring_security_in_login_and_logout_in_spring_boot

3. Maven Dependency

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.11</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.springjava</groupId>
    <artifactId>Spring_Security_Custom_Login_Logout_Example</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>
    <name>Spring_Security_Custom_Login_Logout_Example</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>16</java.version>
    </properties>
    <dependencies>
        <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>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <scope>provided</scope>
        </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>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

4. Create a view page

Create a view page under src/main/resources/templates.

login.html

<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Login</title>
<link
    href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css"
    rel="stylesheet">
</head>
<body>
    <nav class="navbar navbar-expand-lg navbar-dark bg-dark">
        <div class="container-fluid">
            <a class="navbar-brand">Spring Security
                Custom Login-Logout Example</a>
            <button class="navbar-toggler" type="button"
                data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent"
                aria-controls="navbarSupportedContent" aria-expanded="false"
                aria-label="Toggle navigation">
                <span class="navbar-toggler-icon"></span>
            </button>
        </div>
    </nav>
    <br />
    <br />
    <div class="container">
        <div class="row">
            <div class="col-md-6 offset-md-3">

                <div th:if="${param.error}">
                    <div class="alert alert-danger">Invalid Username or Password</div>
                </div>
                <div th:if="${param.logout}">
                    <div class="alert alert-success">You have been logged out.</div>
                </div>

                <div class="card">
                    <div class="card-header">
                        <h2 class="text-center">Login</h2>
                    </div>
                    <div class="card-body">
                        <form method="post" role="form" th:action="@{/login}"
                            class="form-horizontal">
                            <div class="form-group mb-3">
                                <label class="control-label"> Username</label> <input type="text"
                                    id="username" name="username" class="form-control"
                                    placeholder="Enter username" />
                            </div>

                            <div class="form-group mb-3">
                                <label class="control-label"> Password</label> <input
                                    type="password" id="password" name="password"
                                    class="form-control" placeholder="Enter password" />
                            </div>
                            <div class="form-group mb-3">
                                <button type="submit" class="btn btn-primary">Submit</button>
                            </div>
                        </form>
                    </div>
                </div>
            </div>
        </div>
    </div>
</body>
</html>

home.html

<html lang="en"
      xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Home</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css"
          rel="stylesheet">
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
    <div class="container-fluid">
        <a class="navbar-brand">Spring Security Custom Login-Logout Example</a>
        <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
            <span class="navbar-toggler-icon"></span>
        </button>
        <div class="collapse navbar-collapse" id="navbarSupportedContent">
            <ul class="navbar-nav me-auto mb-2 mb-lg-0">
                <li class="nav-item">
                    <a class="nav-link active" aria-current="page" th:href="@{/logout}">Logout</a>
                </li>
            </ul>
        </div>
    </div>
</nav>
<br /><br />
<body>
<div class="container">
    <div class="row">
        <h1> Welcome to Spring Security world!</h1>
    </div>
</div>
</body>
</html>

5. Create a Controller class

HomeController.java

package com.springjava.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class HomeController {
@GetMapping("/")
public String greeting() {
    return "home";
}
@GetMapping("/login")
public String login() {
      return "login";
    }
}

6. Create a Spring Security Config class

SecurityConfig.java

package com.springjava.security;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
public class SecurityConfig {
    @Bean
    public static PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    public SecurityFilterChain securityChain(HttpSecurity http) throws Exception {
        http.csrf().disable().
        authorizeRequests().anyRequest().authenticated()
        .and().formLogin().loginPage("/login")
        .and().formLogin().loginProcessingUrl("/login")
        .and().formLogin().defaultSuccessUrl("/").permitAll()
        .and().logout().logoutSuccessUrl("/login");
    return http.build();
    }

    @Bean
    public UserDetailsService userDetailsService() {

        UserDetails admin = User.builder().username("admin").password(passwordEncoder().encode("admin")).roles("ADMIN")
                .build();

        return new InMemoryUserDetailsManager(admin);
    }
}

7. Run the Application

To run this application right-click on the application click on Run As then select the Run on Server option. After successfully running this application on the browser custom login form is shown. 
Custom Login Form

Enter a valid username and password then click on the Login button of the form.

Click on the Logout to check the custom logout feature.

Enter an invalid username and password to check the error message.


8. How to use different field names and URL in Login in Spring Security?

Spring Security by default uses the field names username and password and the action of the form “/login”. If we want to use customised field names and URL for login we can specify like code below:

http.formLogin()
    .loginPage("/login")
    .usernameParameter("email")
    .passwordParameter("pass")
    .loginProcessingUrl("/do-login");
<form th:action="@{/do-login}" method="post">
    <p>
        E-mail: <input type="email" name="email" required /> 
    </p>
    <p>
        Password: <input type="password" name="pass" required />
    </p>
    <p>
        <input type="submit" value="Login" />
    </p>
</form>

9. Login Success Handler

We can also write code with a success handler for login customization in Spring Security. We can follow like below:

http.formLogin()
.successHandler(new AuthenticationSuccessHandler() {
     
    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
            Authentication authentication) throws IOException, ServletException {
         
        System.out.println("Logged user: " + authentication.getName());
         
        response.sendRedirect("/");
    }
});

10. Logout Success Handler

We can also write code with a logout success handler for logout customization in Spring Security. We can follow like below:

http.logout().
logoutSuccessHandler(new LogoutSuccessHandler() {
                    @Override
                    public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response,
                            Authentication authentication) throws IOException, ServletException {

                        System.out.println("User logged out: " + authentication.getName());

                        response.sendRedirect("/login");
                    }

                });

11. Conclusion

In this example, we learnt how to use customise Spring Security login and logout in the Spring Boot application.

Leave a Comment