Spring Boot Security Custom Form Login Example

Spring Boot Security Custom Form Login Example thumbnail
84K
By Dhiraj 07 December, 2016

In any web app, security has always been a great concern. Today, we will be securing our Spring MVC app using Spring Security login form feature.To build this application we will be using Spring boot to build it and hence we will have a complete javaconfig.We will also take care of protecting the app against Cross Site Request Forgery (CSRF) attacks (Detail here). Now let us build our login app. If the credentials provided in the login form is valid, then user will be redirected to next page. If not an error message will be displayed.

Environment Setup

1. JDK 8 2. Spring Boot 3. Intellij Idea/ eclipse 4. Maven

Maven Dependencies

spring-boot-starter-parent: provides useful Maven defaults. It also provides a dependency-management section so that you can omit version tags for existing dependencies.

spring-boot-starter-web: includes all the dependencies required to create a web app. This will avoid lining up different spring common project versions.

spring-boot-starter-tomcat: enable an embedded Apache Tomcat 7 instance, by default. We have overriden this by defining our version. This can be also marked as provided if you wish to deploy the war to any other standalone tomcat.

tomcat-embed-jasper: provides support for .jsp file rendering.

spring-boot-starter-security: take care of all the required dependencies related to spring security.

pom.xml
    <properties>
        <tomcat.version>8.0.3</tomcat.version>
		<start-class>spring-boot-example.Application</start-class>
    </properties>

	<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.3.3.RELEASE</version>
    </parent>
	
    <dependencies>
		<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-security</artifactId>
		</dependency>
		<dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
		</dependency>
		<dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-jasper</artifactId>
			<!--<scope>provided</scope>-->
		</dependency>
		
    </dependencies>

Spring Bean Configuration

SpringBootServletInitializer enables process used in Servlet 3.0 using web.xml

@SpringBootApplication: This is a convenience annotation that is equivalent to declaring @Configuration, @EnableAutoConfiguration and @ComponentScan.

Application.java
package com.developerstack.config;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.context.web.SpringBootServletInitializer;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@ComponentScan(basePackages = "com.developerstack")
@SpringBootApplication
public class Application extends SpringBootServletInitializer {
	
	 private static Class applicationClass = Application.class;

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

}

By default Spring Boot will serve static content from a directory called /static (or /public or /resources or /META-INF/resources) in the classpath or from the root of the ServletContext. But here we have defined out custom folder structure for static contents, hence it is required to tell Spring boot about how to render static content.

WebConfig.java
package com.developerstack.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.JstlView;

@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {

    @Override
    public void addResourceHandlers(final ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/*.js/**").addResourceLocations("/ui/static/");
        registry.addResourceHandler("/*.css/**").addResourceLocations("/ui/static/");
    }
    
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/").setViewName("login");
        registry.addViewController("/login").setViewName("login");
    }
    
    @Bean
    public InternalResourceViewResolver setupViewResolver()  {
        InternalResourceViewResolver resolver =  new InternalResourceViewResolver();
        resolver.setPrefix ("/ui/jsp/");
        resolver.setSuffix (".jsp");
        resolver.setViewClass (JstlView.class);
        return resolver;
    }

}
 Other Interesting Posts
AES Encryption and Decryption in Java
Spring Security Password Encoding using Bcrypt Encoder
Spring Boot Security Redirect after Login with complete JavaConfig
Spring Security Hibernate Example with complete JavaConfig
Securing REST API with Spring Security Basic Authentication
Spring JMS Activemq Integration with Spring Boot
Websocket spring Boot Integration without STOMP with complete JavaConfig
Maintaining Spring Session during Websocket Connection
Spring MVC Angularjs Integration with complete JavaConfig
Spring Hibernate Integration with complete JavaConfig
Spring Junit Integration with complete JavaConfig
Spring Ehcache Cacheable Example with complete javaConfig
Spring Boot Thymeleaf Example

Now let us define our main configuration for spring security - SpringSecurityConfig.java.class is annotated with @EnableWebSecurity to enable Spring Security web security support. we have extended WebSecurityConfigurerAdapter to override spring features with our custom requirements. Here we are permitting all users to have access to login and logout urls but only authorised users having role as USER should be allowed to view the dashboard page. In the mean time, we have also made configuration to secure our authentication process with CSRF attack.

SpringSecurityConfig.java
package com.developerstack.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
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.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

@Configuration
@EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http.csrf().requireCsrfProtectionMatcher(new AntPathRequestMatcher("**/login")).and().authorizeRequests()
				.antMatchers("/dashboard").hasRole("USER").and().formLogin().defaultSuccessUrl("/dashboard")
				.loginPage("/login").and().logout().permitAll();
	}

	@Autowired
	public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
		auth.inMemoryAuthentication().withUser("john123").password("password").roles("USER");
	}

	@Override
	public void configure(WebSecurity web) throws Exception {
		web.ignoring().antMatchers("/*.css");
		web.ignoring().antMatchers("/*.js");
	}
}

Our controller class is exactly similar to controller which we defined in this article. This controller is responsible to render dashboard page with user details as a model object.

Client Side

Now let us define our login.jsp.Here we have placed a hidden input type with name="${_csrf.parameterName}" and value="${_csrf.token}" which will protect the application against Cross Site Request Forgery (CSRF) attacks.

login.jsp
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
    <title>Spring Security Example</title>
<link href="/bootstrap.min.css" rel="stylesheet">
    <script src="/jquery-2.2.1.min.js"></script>
    <script src="/bootstrap.min.js"></script>
</head>
<body>
	<div class="container" style="margin:50px">
		<h3>Spring Security Login Example</h3>
		<c:if test="${param.error ne null}">
			<div style="color: red">Invalid credentials.</div>
		</c:if>
		<form action="/login" method="post">
			<div class="form-group">
				<label for="username">UserName: <input type="text"
					class="form-control" id="username" name="username">
			</div>
			<div class="form-group">
				<label for="pwd">Password:</label> <input type="password"
					class="form-control" id="pwd" name="password">
			</div>

			<button type="submit" class="btn btn-success">Submit</button>

			<input type="hidden" name="${_csrf.parameterName}"
				value="${_csrf.token}" />
		</form>
	</div>
</body>
</html>

Following is the dashboard.jsp which will be rendered on successful login. It has also a hidden input type with name="${_csrf.parameterName}" and value="${_csrf.token}" to protect the application against Cross Site Request Forgery (CSRF) attacks.

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
    <title>Spring Security Example</title>
<link href="/bootstrap.min.css" rel="stylesheet">
    <script src="/jquery-2.2.1.min.js"></script>
    <script src="/bootstrap.min.js"></script>
</head>
<body>
<div>
<div class="container" style="margin:50px;border: 1px solid green;">
	<div>
		<form action="/logout" method="post">
			<button type="submit" class="btn btn-danger">Log Out</button>
			<input type="hidden" name="${_csrf.parameterName}"
				   value="${_csrf.token}"/>
		</form>
    </div>
    <div class="row text-center"><strong> User Details</strong></div>
    <div class="row" style="border:1px solid green;padding:10px">
        <div class="col-md-4 text-center"><strong>Name</strong></div>
        <div class="col-md-4 text-center"><strong>Email</strong></div>
        <div class="col-md-4 text-center"><strong>Address</strong></div>
    </div>
        <c:forEach var="user" items="${users}">
            <div class="row" style="border:1px solid green;padding:10px">
            <div class="col-md-4 text-center">${user.name}</div>
            <div class="col-md-4 text-center" >${user.email}</div>
                <div class="col-md-4 text-center">${user.address}</div>
            </div>
        </c:forEach>

</div>
</div>
</body>
</html>

Run Application

1. Run Application.java as a java application.

2. Hit the url as http://localhost:8080/dashboard but since the user is not authorised yet, user will be redirected to /login as below:

spring-boot-security-login

3. Now enter any wrong credentials and we can see an error message as follow. This proves our authentication mechanism is working.

spring-boot-security-login-error

4. Enter the username/password as john123/password and hit enter the dashboard page will be rendered.

spring-boot-security-dashboard

5. Here we can see a logout button, once clicked the user will be successfuly logged out and redirected to the login page.

Conclusion

I hope this article served you that you were looking for. If you have anything that you want to add or share then please share it below in the comment section.

Download the source

Share

If You Appreciate This, You Can Consider:

We are thankful for your never ending support.

About The Author

author-image
A technology savvy professional with an exceptional capacity to analyze, solve problems and multi-task. Technical expertise in highly scalable distributed systems, self-healing systems, and service-oriented architecture. Technical Skills: Java/J2EE, Spring, Hibernate, Reactive Programming, Microservices, Hystrix, Rest APIs, Java 8, Kafka, Kibana, Elasticsearch, etc.

Further Reading on Spring Security