If you are here, means you know how to configure spring boot security in an application. Spring security provides a default login form shown below as a part of its auto-configuration.

spring security login page

But many times you don’t need want to go with default login page, probably custom design is the primary requirement or the application might have a login form and you want to reuse it.
This article will explain how to display a custom login page with spring boot security.


Creating a custom configuration
In Spring boot security, if you want to deviate from any of its auto configuration, then you have to define a class which
1. extends WebSecurityConfigurerAdapter, and
2. has @EnableWebSecurity annotation applied to it.

When you write a class with above 2 attributes, you are telling Spring security that I will not be using default security configuration but customizing it according to my requirements.
Configuring custom login page
By providing a custom configuration security class, you can override methods provided by Spring security. One of these methods is

protected void configure(HttpSecurity http) throws Exception {

}

If you do not override this method, then default implementation is

http.
authorizeRequests().
anyRequest().
authenticated().
and().
formLogin().
and().
httpBasic();

which says authenticate all requests based on a form login.

It is after formLogin() method that we will be instructing Spring security to display our own login form as shown highlighted below.

package com.codippa.security;

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;

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
   @Override
   protected void configure(HttpSecurity http) throws Exception {
     http.
     authorizeRequests().
     anyRequest().
     authenticated().
     and().
     formLogin().
     loginPage("/login").
     permitAll();
   }
}

Above code tells Spring security to invoke “/login” URL before displaying login form. It is not mandatory for the URL to be “/login”, could be anything.


In the above code,

1. authorizeRequests() : Tells Spring security to check for authentication of requests. This method is required for calling all other subsequent methods.
2. anyRequest().authenticate() : Asks Spring security to authenticate every request and allow only authenticated requests to pass through.
3. permitAll() after loginPage("/login") instructs Spring security to allow all users(even unauthenticated), access to this URL.
In the absence of permitAll(), you will not be able to see login page.

We also need to provide a mapping for this URL in our application in a controller class as given below.

package com.codippa.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;

@Controller
public class AppController {

  @GetMapping("/login")
  public String login() {
    return "login";
  }
 
}

When Spring calls this URL, it returns a String.
Now it searches for the appropriate view matching this String as per the view technology configured.

This example uses Thymeleaf. If you are not familiar with Spring boot and Thymeleaf integration, refer this article.

Thymeleaf uses html templates so the String returned from controller method mapped to “/login” URL refers to a template called login.html template.
This template can be placed in src/main/resources/templates folder which is the default template location for Spring boot or you can change thymeleaf template location as required. It will pick up from there.

Template code for login page is given below.

<html xmlns:th="http://www.thymeleaf.org"> 
  <h1>Please Login!</h1> 
  <hr /> 
  <form th:action="@{/authenticate}" method="post"> 
    <fieldset> 
      <legend>Please Login</legend> 
      <label for="username">Username</label> 
      <input type="text" id="username" name="username" /> 
      <label for="password">Password</label> 
      <input type="password" id="password" name="password"/> 
      <div class="form-actions"> 
        <button type="submit" class="btn">Log in</button> 
      </div> 
    </fieldset> 
  </form> 
</html>

Note the th:action attribute, this is Thymeleaf specific.

This form when submitted will invoke a URL “/authenticate” so we also need to create a method mapped to this URL in our controller as shown below.

@PostMapping("/authenticate")
public String authenticate() {
   return "welcome";
}

This method will only be called when you enter correct username and password.
You can write your own authentication logic inside authenticate method. But if you write nothing, then this username and password will be authenticated by Spring.

Now the question arises, what is the username and password. There are multiple ways to create a username and password in Spring boot security.
For now, add below entries in application.properties file regarding username and password.

 

spring.security.user.name=admin
spring.security.user.password=1234

Once authenticated, it will return a template named “welcome”. So, we need to create another template as shown below.

<html xmlns:th="http://www.thymeleaf.org">

   <h1 th:text="Welcome"></h1>

   <h1>You are logged in!!</h1>
</html>

One last thing…
Login page submits to(or invokes) a URL “/authenticate” but in the security configuration, we only granted access to URL “/login” to all users.

So, for this URL to get invoked, we also need to allow it in the security configuration. Thus, updated security configuration will look like,

@Override
protected void configure(HttpSecurity http) throws Exception {
  http.
  authorizeRequests().
  antMatchers("/message").permitAll().
  anyRequest().
  authenticated().
  and().
  formLogin().
  loginPage("/login").
  permitAll();
}

Complete controller class will be as below.

package com.codippa.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;

@Controller
public class AppController {

  @PostMapping("/authenticate")
  public String authenticate() {
    // authentication logic here
    return "welcome";
  }
  
  @GetMapping("/login")
  public String login() {
    return "login";
  }
}
Spring boot security custom login page

Screenshots
Start application and access URL http://localhost:8080, below login page will display,

Enter username and password, admin and 1234, respectively, and below page will be displayed.

Welcome

You are logged in!!

Note that this article does not explain form submission in Thymeleaf, it only explains how a custom login form is displayed in Spring boot security and what configurations are required for that.
For learning how to submit a form in Thymeleaf, you can refer this article.

Hope the article was useful.

Leave a Reply