Spring Security + Thymeleaf Login and Logout Example

By Arvind Rai, June 25, 2019
On this page we will provide Spring Security and Thymeleaf integration custom login page and logout example with CSRF token using JavaConfig. We can create our login and logout form using thymeleaf. Spring Security JavaConfig enables CSRF protection by default. With the use of @EnableWebSecurity annotation, thymeleaf includes CSRF token within form automatically. Logout form must be submitted as POST when using CSRF protection. Here we will use spring boot for spring and thymeleaf JAR dependencies. In our application we are creating a student detail page that can be accessed only after successful authentication. Find the complete example step by step.

Software Used

Find the software used in our demo.
1. Java 8
2. Spring 4.2.5.RELEASE
3. Tomcat 8
4. Gradle
5. Eclipse

Project Structure in Eclipse

Find the print screen of project structure in eclipse.
Spring 4 Security + Thymeleaf Integration Custom Login Page and Logout Example with CSRF Token using JavaConfig

Gradle to Build Project

Find the gradle file to resolve the JAR dependences and build the project.
build.gradle
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'war'
archivesBaseName = 'spring4javaconfig'
version = '1' 
repositories {
    mavenCentral()
}
dependencies {
    compile 'org.springframework.boot:spring-boot-starter-web:1.3.3.RELEASE'
    compile 'org.springframework.boot:spring-boot-starter-security:1.3.3.RELEASE'
    compile 'org.springframework.boot:spring-boot-starter-thymeleaf:1.3.3.RELEASE'    
    providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat:1.3.3.RELEASE'    
} 

Create Login Form using Thymeleaf with CSRF Token

We will create login form using Thymeleaf. The value for action, user name and password attributes used in authentication are the custom values which has been defined in our spring security configuration using JavaConfig. In case we are using Thymeleaf to create spring security login form and spring security configuration is using @EnableWebSecurity annotation, then CSRF token is automatically included within form at runtime. Spring security JavaConfig enables CSRF protection by default. We need to submit form using POST method.
customLogin.html
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
    <head>
        <title> Spring 4 Security + Thymeleaf Integration Example </title>
    </head>
    <body>
        <h3> Spring 4 Security + Thymeleaf Integration Example </h3> 
        <p th:if="${param.error}">
            Bad Credentials  
        </p>
        <form th:action="@{/appLogin}" method="POST">
            User Name : <input type="text" name="app_username"/> <br/><br/>
            Password: <input type="password" name="app_password"/> <br/><br/>
            <input type="submit" value="Login"/>
        </form>
    </body>
</html> 
CSRF token will be included at runtime by Thymeleaf because of @EnableWebSecurity annotation. We are catching default error query parameter to display error message.

Create Logout Form using Thymeleaf in Secure Views

In our example we are creating a secure view in which student details are being shown using Thymeleaf. We have created a logout form using Thymeleaf. CSRF token will be included at run time automatically by Thymeleaf. As we are using CSRF protection, we must submit logout form using POST method.
student.html
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>
      <title>Spring 4 Security + Thymeleaf Integration Example</title>
</head>
<body>
   <h3>Spring 4 Security + Thymeleaf Integration Example </h3>
    Logged in user: <b th:inline="text"> [[${#httpServletRequest.remoteUser}]] </b>	 
    <form th:action="@{/appLogout}" method="POST">
         <input type="submit" value="Logout"/>
    </form>
    <table>
	  <tr th:each="student : ${students}">
            <td th:text="${student.stdId}">Id</td>
	    <td th:text="${student.stdName}">Name</td>
	  </tr>
    </table>
</body>
</html>    

Spring Security and Thymeleaf Configuration using JavaConfig

Find the spring security and thymeleaf configuration using JavaConfig.
SecurityConfig.java
package com.concretepage.config;
import org.springframework.beans.factory.annotation.Autowired;
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().
		antMatchers("/app/secure/**").access("hasAnyRole('ROLE_ADMIN', 'ROLE_USER')").
		and().formLogin().  //login configuration
                loginPage("/app/login").
                loginProcessingUrl("/appLogin").
                usernameParameter("app_username").
                passwordParameter("app_password").
                defaultSuccessUrl("/app/secure/studentDetail").	
		and().logout().    //logout configuration
		logoutUrl("/appLogout"). 
		logoutSuccessUrl("/app/login");
	} 
	@Autowired
	public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
		auth.inMemoryAuthentication().withUser("ramesh").password("ram123").roles("ADMIN");
		auth.inMemoryAuthentication().withUser("mahesh").password("mah123").roles("USER");
	}	
} 
ThymeleafConfig.java
package com.concretepage.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.thymeleaf.spring4.SpringTemplateEngine;
import org.thymeleaf.spring4.view.ThymeleafViewResolver;
import org.thymeleaf.templateresolver.ServletContextTemplateResolver;
@Configuration 
@ComponentScan("com.concretepage") 
@EnableWebMvc
@Import(SecurityConfig.class)
public class ThymeleafConfig extends WebMvcConfigurerAdapter  {
    @Bean(name ="templateResolver")	
    public ServletContextTemplateResolver getTemplateResolver() {
    	ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver();
    	templateResolver.setPrefix("/WEB-INF/templates/");
    	templateResolver.setSuffix(".html");
    	templateResolver.setTemplateMode("XHTML");
	return templateResolver;
    }
    @Bean(name ="templateEngine")	    
    public SpringTemplateEngine getTemplateEngine() {
    	SpringTemplateEngine templateEngine = new SpringTemplateEngine();
    	templateEngine.setTemplateResolver(getTemplateResolver());
	return templateEngine;
    }
    @Bean(name="viewResolver")
    public ThymeleafViewResolver getViewResolver(){
    	ThymeleafViewResolver viewResolver = new ThymeleafViewResolver(); 
    	viewResolver.setTemplateEngine(getTemplateEngine());
	return viewResolver;
    }
} 

Web Application Initializer

Find the web application initializer for DelegatingFilterProxy.
SecurityInitializer.java
package com.concretepage.config;
import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;
public class SecurityInitializer extends AbstractSecurityWebApplicationInitializer {
}
Find the web application initializer for DispatcherServlet.
WebAppInitializer.java
package com.concretepage.config;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
	@Override
	protected Class<?>[] getRootConfigClasses() {
		return new Class[] { ThymeleafConfig.class };
	}
	@Override
	protected Class<?>[] getServletConfigClasses() {
		return null;
	}
	@Override
	protected String[] getServletMappings() {
		return new String[] { "/" };
	}
}  

Create Controller and Service Class

Find the spring MVC controller and service class used in our example.
StudentController.java
package com.concretepage.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import com.concretepage.service.StudentService;
@Controller
@RequestMapping("/app")
public class StudentController {
	@Autowired
        private StudentService service;
	@RequestMapping(value="/login")
	public String homePage() {
 		return "customLogin";
 	}    
	@RequestMapping(value="/secure/studentDetail")
	public String studentDetail(Model model) {
		model.addAttribute("students", service.getStudents());
 		return "student";
 	}
} 
StudentService.java
package com.concretepage.service;
import java.util.ArrayList;
import java.util.List;
import org.springframework.stereotype.Service;
import com.concretepage.bean.Student;
@Service
public class StudentService {
	List<Student> list = new ArrayList<>();
	{
		list.add(new Student(1, "Ram"));
		list.add(new Student(2, "Shyam"));
		list.add(new Student(3, "Rahim"));
	}
	public List<Student> getStudents() {
		return list;
	}
} 
Student.java
package com.concretepage.bean;
public class Student {
	private int stdId;
	private String stdName;
	public Student(){}
	public Student(int stdId, String stdName) {
		this.stdId = stdId;
		this.stdName = stdName;
	}
	public int getStdId() {
		return stdId;
	}
	public void setStdId(int stdId) {
		this.stdId = stdId;
	}
	public String getStdName() {
		return stdName;
	}
	public void setStdName(String stdName) {
		this.stdName = stdName;
	}
} 

Run Application

To run the application find the below steps.
1. Download the project source code.
2. Go to root directory of the project using command prompt.
3. Run gradle clean build
4. We will get WAR file in build/lib directory.
5. Deploy WAR file in tomcat.
6. Run the application using URL http://localhost:8080/spring4javaconfig-1/app/login

We will get below print screen.
Spring 4 Security + Thymeleaf Integration Custom Login Page and Logout Example with CSRF Token using JavaConfig
Use username/password as ramesh/ram123 or mahesh/mah123, we will get print screen as given below.
Spring 4 Security + Thymeleaf Integration Custom Login Page and Logout Example with CSRF Token using JavaConfig
After logged out, it goes to login page.

Download Complete Source Code

POSTED BY
ARVIND RAI
ARVIND RAI







©2024 concretepage.com | Privacy Policy | Contact Us