3 min read

Custom Form Login in Spring Security

December 20, 2020

The default form login that you have seen in my previous post may not fit everyone’s need. For example, Some organization may want to put a logo on their login page. Some may find the default login forms less appealing. For some perfectionists, The default password may not seem to fit the theme of the whole application. So it makes sense if someone wants to provide their implementation of the login page.

The idea here is that the path /login should return an HTML containing a form. To do that, we need to the following.

Add thymeleaf view support

Add thymeleaf starter as dependency. We need this starter because Spring MVC need a view resolver to map a path to a view template.

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

Custom login page

Create a file called src/main/resources/views/login.html For this, I have created a simple HTML with the following content.

<!DOCTYPE html>
<html lang="en" xmlns:th="https://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">

    <link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/tailwindcss/2.0.2/tailwind.min.css">
    <title>Login : Demo</title>
</head>
<body class="h-screen">
<div class="container mx-auto h-full flex justify-center items-center text-green-700 px-4">
    <div class="md:w-1/3 shadow-xl rounded-2xl border bg-green-100 w-full">
        <h1 class="text-center font-medium text-2xl text-white rounded-t-2xl bg-green-500 py-4">Sign In</h1>
        <form th:action="@{/login}" method="post" class="border-teal p-4 border-t-12 bg-white mb-6">
            <div class="mb-4">
                <label for="username" class="font-bold text-lg block mb-2">Username</label>
                <input id="username" type="text" name="username" autocomplete="off"
                       class="block w-full rounded p-2 rounded shadow border focus:outline-none focus:ring-2 focus:ring-green-600 focus:border-transparent"
                       placeholder="Your Username">
            </div>

            <div class="mb-4">
                <label for="password" class="font-bold text-lg block mb-2">Password</label>
                <input id="password" type="password" name="password" autocomplete="off"
                       class="block w-full rounded p-2 rounded shadow border focus:outline-none focus:ring-2 focus:ring-green-600 focus:border-transparent"
                       placeholder="Your Password">
            </div>
            <div class="flex items-center justify-between">
                <input class="bg-green-500 text-white text-lg font-medium p-2 rounded inline-block w-full hover:bg-green-400 transition duration-400 hover:shadow-lg"
                       type="submit" value="Login">
            </div>

        </form>
        <div class="text-center pb-4">
            <p class="text-grey-dark text-sm">
                Don't have an account? <a href="#" class="no-underline text-green-500 font-bold">Create an Account</a>.
            </p>
        </div>
    </div>
</div>
</body>
</html>

Configure Spring MVC

Map this login.html to the path /login. For this step, you need to provide a custom WebMvcConfigurer to let spring MVC know that you are registering a new mapping for login as shown below.

package com.springhow.examples.springboot.security.customformlogin.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/login").setViewName("login");
    }
}

By doing this configuration, The MVC context will look for login.html under src/main/resources/templates/ whenever a request comes to /login.

Spring Security java configuration

Finally, override the default HttpSecurity configuration as shown below.

package com.springhow.examples.springboot.security.customformlogin.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

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

If all the above are done correctly, Then on requesting http://localhost:8080/hello would redirect to a custom login page as shown below. Custom Login form with our own CSS

Sample code for this project is on the github link below.