Spring MVC Security Login and Logout Example
June 25, 2019
This page will walk through Spring MVC Security custom login form and logout example with CSRF protection using annotation and XML configuration. Spring Security provides a login form by default and if we want to use our custom login form, we can achieve it by using spring security annotation as well as XML configuration. Spring security provides default URLs for login and logout which can be changed as required using JavaConfig as well as XML configuration. In spring 4 security, CSRF protection is enabled by default in XML configuration as in JavaConfig. We can disable and enable CSRF protection as required. If we are using CSRF protection, the logout request must be POST. Here we will create a spring security application that will provide an UI to get student detail by entering the student id. We will use in-memory authentication creating a user with a user name, password and role. Here we will provide complete example with annotation and XML configuration step by step.
Contents
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
Gradle File to Build Project
Find the gradle file to build the project and resolve the JAR dependencies.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' providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat:1.3.3.RELEASE' }
Spring 4 Security and CSRF
CSRF is Cross Site Request Forgery. Spring security protects our application from CSRF. In JavaConfig, CSRF protection is enabled by default. Now Spring security version 4 onwards XML configuration is also CSRF protection enabled by default. We can disable CSRF protection if required. Find the below points regarding CSRF protection to use in our spring security application.1. To use CSRF protection in our views, include a hidden HTML field within <form>.
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
3. Find the XML configuration to disable CSRF protection.
<http> <!-- Other Configurations --> <csrf disabled="true"/> </http>
protected void configure(HttpSecurity http) throws Exception { http.csrf().disable(); }
Spring 4 MVC Security Custom Login Form and Logout Example using Annotation
Here we will create a spring 4 MVC security custom login form and logout example using annotation. The configurations related to custom login form and logout are done in JavaConfig. We will create two configuration file, one for spring security configuration and another for spring MVC configuration. We will create a service class that will provide student detail and will create views for the same which will be secured and can be accessed only after authentication. We will use in-memory user authentication. We will handle CSRF protection in our form by including a hidden field for CSRF parameter. Spring security enables CSRF protection in JavaConfig by default.Project Structure in Eclipse for JavaConfig
Find the print screen of project structure in eclipse with JavaConfig.
Create JavaConfig for Spring Security
Find the JavaConfig used in our spring security custom login and logout application.SecurityConfig.java
package com.concretepage.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.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests(). antMatchers("/secure/**").access("hasRole('ROLE_ADMIN')"). and().formLogin(). //login configuration loginPage("/customLogin.jsp"). loginProcessingUrl("/appLogin"). usernameParameter("app_username"). passwordParameter("app_password"). defaultSuccessUrl("/secure/home"). and().logout(). //logout configuration logoutUrl("/appLogout"). logoutSuccessUrl("/customLogin.jsp"); } @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication().withUser("ram").password("ram123").roles("ADMIN"); } }
authorizeRequests(): It allows restricted access. HTTP requests are authorized before being served.
antMatchers(): It matches the URL with given pattern.
access(): It checks if the USER has provided role.
formLogin(): Enables form based authentication.
loginPage(): It specifies the custom login page URL.
loginProcessingUrl(): It specifies the URL using which username and password is validated.
usernameParameter(): It specifies the field name to enter user name which is used by spring security to validate. If not specified then default is username.
passwordParameter(): It specifies the field name to enter password which is used by spring security to validate. If not specified then default is password.
defaultSuccessUrl(): It specifies the default URL which is used by spring security after successful authentication.
logout(): It support the logout functionality in spring security application.
logoutUrl(): If defines the URL for logout. If CSRF protection is enabled, logout request must be POST.
logoutSuccessUrl(): It specifies the URL which is used by spring security after successful logout.
configureGlobal(): It configures
AuthenticationManager
. Here we are using in-memory authentication in our example.
Create JavaConfig for Spring MVC
Find the JavaConfig for spring MVC.AppConfig.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.view.InternalResourceViewResolver; @Configuration @ComponentScan("com.concretepage") @Import(SecurityConfig.class) @EnableWebMvc public class AppConfig { @Bean public InternalResourceViewResolver viewResolver() { InternalResourceViewResolver resolver = new InternalResourceViewResolver(); resolver.setPrefix("/WEB-INF/secure/"); resolver.setSuffix(".jsp"); return resolver; } }
@EnableWebMvc: This annotation imports web MVC configuration from
WebMvcConfigurationSupport
.
InternalResourceViewResolver: Using prefix and suffix, URL is created to access internal resource.
Create Custom Login Form
We need to create a form which action will be defined byhttp.loginProcessingUrl()
and user name and password field name will be defined as specified by htt.usernameParameter()
and http.passwordParameter()
respectively. As CSRF protection is enabled, we need to include a hidden field for CSRF. We need to submit the form using POST method.
customLogin.jsp
<html> <head> <title>Spring 4 Security Example</title> </head> <body> <h3>Spring 4 Security Example</h3> <font color="red"> ${SPRING_SECURITY_LAST_EXCEPTION.message} </font> <form action="<%=request.getContextPath()%>/appLogin" method="POST"> Enter UserName: <input type="text" name="app_username"/><br/><br/> Enter Password: <input type="password" name="app_password"/> <br/><br/> <input type="submit" value="Login"/> <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/> </form> <body> </html>
Create Logout form in Secure Views
In our case CSRF protection is enabled which is default behavior of spring 4 security. Hence logout request must be submitted as POST. We have created a HTML form whose action is defined with the value specified byhttp.logoutUrl()
in security configuration. We will include a hidden tag for CSRF within our HTML form.
home.jsp
<html> <head> <title>Spring 4 Security Example</title> </head> <body> Welcome! To get student detail <a href="<%=request.getContextPath()%>/secure/studentDetail">click here.</a> <form action="<%=request.getContextPath()%>/appLogout" method="POST"> <input type="submit" value="Logout"/> <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/> </form> </body> </html>
<%@taglib uri="http://www.springframework.org/tags/form" prefix="form"%> <html> <head><title>Spring 4 Security Example</title></head> <body> <h3>Spring 4 Security Example </h3> <form:form action="result" method="POST" commandName="student"> <form:input path="stdId"/> <br/> <input type="submit" value="Submit"> </form:form> </body> </html>
student.jsp
that in case we are using spring <form:form>
tag, we need not to include hidden HTML field for CSRF parameter.
output.jsp
<html> <head> <title>Spring 4 Security Example</title> </head> <body> <h3>Spring 4 Security Example</h3> Student Name: ${stdName} <form action="<%=request.getContextPath()%>/appLogout" method="POST"> <input type="submit" value="Logout"/> <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/> </form> </body> </html>
Create Spring Web Application Initializer
To registerDelegatingFilterProxy
using Servlet 3 without web.xml, we need to create a class which will implement AbstractSecurityWebApplicationInitializer
.
SecurityInitializer.java
package com.concretepage.config; import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer; public class SecurityInitializer extends AbstractSecurityWebApplicationInitializer { }
DispatcherServlet
we will create a class which will implement AbstractAnnotationConfigDispatcherServletInitializer
.
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[] { AppConfig.class }; } @Override protected Class<?>[] getServletConfigClasses() { return null; } @Override protected String[] getServletMappings() { return new String[] { "/" }; } }
Create Service and Controller Class
We are creating a service that will provide student detail by student id and will be assed in controller.StudentService.java
package com.concretepage.service; import java.util.HashMap; import java.util.Map; import org.springframework.stereotype.Service; import com.concretepage.bean.Student; @Service public class StudentService { Map<Integer, Student> map = new HashMap<>(); { map.put(1, new Student(1, "Ram")); map.put(2, new Student(2, "Shyam")); map.put(3, new Student(3, "Rahim")); } public String getStudentName(int id) { System.out.println("Fetching student for the id:"+ id); Student std = map.get(id); return std.getStdName(); } }
package com.concretepage.controller; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.ui.ModelMap; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import com.concretepage.bean.Student; import com.concretepage.service.StudentService; @Controller @RequestMapping("/secure") public class StudentController { @Autowired private StudentService service; @RequestMapping(value="/home") public String homePage() { return "home"; } @RequestMapping(value="/studentDetail") public String studentDetail(Model model) { model.addAttribute("student", new Student()); return "student"; } @RequestMapping(value="/result", method=RequestMethod.POST) public String success(@ModelAttribute("student") Student student, ModelMap model) { String stdName = service.getStudentName(student.getStdId()); model.addAttribute("stdName", stdName); return "output"; } }
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; } }
Spring 4 MVC Security Custom Login Form and Logout Example using XML Configuration
Here we will create spring 4 MVC security custom login form and logout example using XML configuration. We will create a spring context XML file equivalent to spring security JavaConfig. The controller, service and views with custom login and logout page will be same as used in our spring security application using annotation. Spring security version 4 onwards, CSRF protection is enabled by default in XML configuration as in JavaConfig. We will use in-memory user authentication.Project Structure in Eclipse for XML Configuration
Find the print screen of our project structure in eclipse with XML configuration.
Create XML Configuration for Spring Security
We are creating a spring context xml file for spring security which is equivalent toSecurityConfig
class created in spring security project using JavaConfig.
security-config.xml
<beans:beans xmlns="http://www.springframework.org/schema/security" xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd"> <http auto-config="true"> <intercept-url pattern="/secure/**" access="hasRole('ROLE_ADMIN')" /> <form-login login-page="/customLogin.jsp" login-processing-url="/appLogin" username-parameter="app_username" password-parameter="app_password" default-target-url="/secure/home"/> <logout logout-url="/appLogout" logout-success-url="/customLogin.jsp"/> </http> <authentication-manager> <authentication-provider> <user-service> <user name="ram" password="ram123" authorities="ROLE_ADMIN" /> </user-service> </authentication-provider> </authentication-manager> </beans:beans>
<http>: It contains elements of HTTP security configuration.
auto-config: If the value is true, it registers basic spring security configuration.
<intercept-url> : It defines URL pattern accessible for specified role using pattern and access attribute.
pattern: Defines URL pattern.
access : Defines roles accessible for the given URL pattern.
<form-login>: Configures form login.
login-page : Defines custom login page URL.
login-processing-url : Defines URL used for authentication using username and password.
username-parameter: Defines field name for username.
password-parameter : Defines field name for password.
default-target-url : Defines default target URL used by spring security after successful login.
<logout>: Defines logout configuration.
logout-url: Defines logout URL used by spring security for logout.
logout-success-url: Defines URL used by spring security after successful logout.
<authentication-manager> : It registers
AuthenticationManager
.
<authentication-provider> : Authentication provider that defines user service for authentication.
<user-service> : It creates in-memory
UserDetailsService
.
<user> : It creates a user with user name, password and roles.
Create Spring Context XML
In spring context XML, we usingcomponent-scan
which will auto detect the service class used in our example. To access internal resource , we have configured InternalResourceViewResolver
which will specify prefix and suffix for the URL redirected by spring MVC controller.
dispatcher-servlet.xml
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <context:component-scan base-package="com.concretepage" /> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/secure/"/> <property name="suffix" value=".jsp"/> </bean> </beans>
web.xml with Spring Security Configuration
Find web.xml used in our spring security application with XML configuration.web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0"> <display-name>Spring 4 Security Example</display-name> <servlet> <servlet-name>dispatcher</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>dispatcher</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <context-param> <param-name>contextConfigLocation</param-name> <param-value> /WEB-INF/dispatcher-servlet.xml, /WEB-INF/security-config.xml </param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- Spring Security Configuration --> <filter> <filter-name>springSecurityFilterChain</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> </filter> <filter-mapping> <filter-name>springSecurityFilterChain</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> </web-app>
DispatcherServlet: It handles HTTP request in spring MVC.
ContextLoaderListener : It listens to start and stop spring
WebApplicationContext
DelegatingFilterProxy : This is a proxy for Servlet filter to delegate to spring managed bean.
Run Application
To run our spring security application, use the below URLs.1. To run spring security application using annotation, find the URL.
http://localhost:8080/spring4javaconfig-1/customLogin.jsp
2. To run the spring security application using XML configuration, find the URL.
http://localhost:8080/spring4xml-1/customLogin.jsp
Find the screen shots of the output. Enter username/password as ram/ram123




Now I am done. Happy spring security learning!