Tutorial

Spring 4 Security MVC Login Logout Example

Published on August 4, 2022
author

Pankaj

Spring 4 Security MVC Login Logout Example

Today we will learn about Spring Security Login Example. Before reading this post, please go through my previous post at “Introduction to Spring 4 Security” to get some basics.

Spring Security Login Logout Example

In this post, we are going to develop Spring 4 MVC Security Web Application to provide Login and Logout features by using In-Memory option. This example uses Spring Java Config with Spring Annotations, that means without using web.xml and Spring XML Configuration(Old Style). If you are not familiar with Spring 3.x Security Module, please go through the following posts first to taste the Spring Security Recipe.

  1. Spring MVC Security Example using in-memory, UserDetailsService and JDBC Authentication
  2. Spring Security in Servlet Web Application using DAO, JDBC, In-Memory authentication

Spring 4 Security Module supports the following options to store and manage User Credentials:

  1. In-Memory Store
  2. Relations Databases(RDBMS)
  3. No SQL Data Stores
  4. LDAP

We will use “In-Memory Store” option in this example. We will discuss other options in my coming posts. We are going to use Spring 4.0.2.RELEASE, Spring STS 3.7 Suite IDE, Spring TC Server 3.1 with Java 1.8 and Maven build tool to develop this example.

Spring Security Login Example

We are going to develop a Login and Logout logic using Spring 4 Security Features. The main aim of this application is that developing an application without using “web.xml” and without writing a single line of Spring XML Beans Configuration. That means we are going to use Spring Java Config feature with Spring Annotations. We will develop this application with the following features:

  1. Welcome Page
  2. Login Page
  3. Home Page
  4. Logout Feature

Please use the following steps to develop and explore this Spring 4 Security Simple Login Example.

  • Create a “Simple Spring Web Maven” Project in Spring STS Suite with the following details
   Project Name : SpringMVCSecruityMavenApp
  • Update pom.xml with the following content
<?xml version="1.0" encoding="UTF-8"?>
<project
   xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 
   https://maven.apache.org/xsd/maven-4.0.0.xsd"
   xmlns="https://maven.apache.org/POM/4.0.0" 
   xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance">

	<modelVersion>4.0.0</modelVersion>
	<groupId>com.journaldev</groupId>
	<artifactId>SpringMVCSecruityMavenApp</artifactId>
	<packaging>war</packaging>
	<version>1.0</version>

	<properties>
	    <java.version>1.8</java.version>
	    <spring.version>4.0.2.RELEASE</spring.version>
	    <spring.security.version>4.0.2.RELEASE</spring.security.version>
	    <servlet.api.version>3.1.0</servlet.api.version>
	    <jsp.api.version>2.2</jsp.api.version>
	    <jstl.version>1.2</jstl.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-core</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-web</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.security</groupId>
			<artifactId>spring-security-web</artifactId>
			<version>${spring.security.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.security</groupId>
			<artifactId>spring-security-config</artifactId>
			<version>${spring.security.version}</version>
		</dependency>
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>javax.servlet-api</artifactId>
			<version>${servlet.api.version}</version>
		</dependency>		
		<dependency>
			<groupId>javax.servlet.jsp</groupId>
			<artifactId>jsp-api</artifactId>
			<version>${jsp.api.version}</version>
		</dependency>
		<dependency>
			<groupId>jstl</groupId>
			<artifactId>jstl</artifactId>
			<version>${jstl.version}</version>
		</dependency>
	</dependencies>	

	<build>
	    <finalName>SpringMVCSecruityMavenApp</finalName>
	    <plugins>
		<plugin>
		     <groupId>org.apache.maven.plugins</groupId>
		     <artifactId>maven-compiler-plugin</artifactId>
		     <version>3.1</version>
		     <configuration>
			<source>${java.version}</source>
			<target>${java.version}</target>
		     </configuration>
		</plugin>
		<plugin>
	           <groupId>org.apache.maven.plugins</groupId>
	           <artifactId>maven-war-plugin</artifactId>
	           <configuration>
	              <failOnMissingWebXml>false</failOnMissingWebXml>
	           </configuration>           
        	</plugin>
	    </plugins>
	</build>
</project>

NOTE:- If you are not aware of “<failOnMissingWebXml>” flag, please read at the end of this post to get a good understanding of this element usage.- First, Develop Login Controller by using Spring’s @Controller annotation. LoginController.java

package com.journaldev.spring.web.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class LoginController {

	@RequestMapping(value = { "/"}, method = RequestMethod.GET)
	public ModelAndView welcomePage() {
		ModelAndView model = new ModelAndView();
		model.setViewName("welcomePage");
		return model;
	}

	@RequestMapping(value = { "/homePage"}, method = RequestMethod.GET)
	public ModelAndView homePage() {
		ModelAndView model = new ModelAndView();
		model.setViewName("homePage");
		return model;
	}
	
	@RequestMapping(value = "/loginPage", method = RequestMethod.GET)
	public ModelAndView loginPage(@RequestParam(value = "error",required = false) String error,
	@RequestParam(value = "logout",	required = false) String logout) {
		
		ModelAndView model = new ModelAndView();
		if (error != null) {
			model.addObject("error", "Invalid Credentials provided.");
		}

		if (logout != null) {
			model.addObject("message", "Logged out from JournalDEV successfully.");
		}

		model.setViewName("loginPage");
		return model;
	}

}

Code Explanation:- We have defined three methods in “LoginController” to handle three different kinds of Client Requests

  1. welcomePage() will handle all client requests which are using “/” URI.
  2. homePage() will handle all client requests which are using “/homePage” URI.
  3. loginPage() will handle all client requests which are using “/loginPage” URI.
  4. In loginPage(), we have take care of handling error and logout messages.
  • Then develop a class “LoginSecurityConfig” to provide Login and Logout Security Features using Spring 4 Security API. LoginSecurityConfig.java
package com.journaldev.spring.secuity.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 LoginSecurityConfig extends WebSecurityConfigurerAdapter {

	@Autowired
	public void configureGlobal(AuthenticationManagerBuilder authenticationMgr) throws Exception {
		authenticationMgr.inMemoryAuthentication()
			.withUser("journaldev")
			.password("jd@123")
			.authorities("ROLE_USER");
	}
	
	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http.authorizeRequests()
			.antMatchers("/homePage").access("hasRole('ROLE_USER')")
			.and()
				.formLogin().loginPage("/loginPage")
				.defaultSuccessUrl("/homePage")
				.failureUrl("/loginPage?error")
				.usernameParameter("username").passwordParameter("password")				
			.and()
				.logout().logoutSuccessUrl("/loginPage?logout"); 
		
	}
}

Code Explanation:- We have defined two methods in “LoginSecurityConfig” to store and manage User Credentials and take care of Login and Logout Security features.

  1. @EnableWebSecurity Annotation is used to enable web security in any web application.
  2. @EnableWebMVCSecurity Annotation is used to enable web security in Spring MVC based web application. NOTE:- @EnableWebSecurity = @EnableWebMVCSecurity + Extra features. That’s why @EnableWebMVCSecurity Annotation is deprecated in Spring 4.x Framework.4. “LoginSecurityConfig” class or any class which is designated to configure Spring Security, should extend “WebSecurityConfigurerAdapter” class or implement related interface.
  3. configureGlobal() method is used to store and mange User Credentials.
  4. In configureGlobal() method, we can use authorities() method to define our application Roles like “ROLE_USER”. We can also use roles() method for same purpose.
  5. Difference between authorities() and roles() methods:
  6. authorities() needs a complete role name like “ROLE_USER” roles() needs a role name like “USER”. It will automatically add “ROLE_” value to this “USER” role name. NOTE:- We will develop another example to demonstrate Roles like “USER”,“ADMIN” in my coming posts.
  7. Important method to take care of Login and Logout Security is configure(HttpSecurity http)
  8. The following code snipped is used to avoid unauthorized access to “/homePage”. If you try to access this page directly, we will redirected to “/loginPage” page automatically.
.antMatchers("/homePage").access("hasRole('ROLE_USER')")

If we remove access(“hasRole(‘ROLE_USER’)”) method call, then we can access this page without login to our application.13. We have configured login and logout features using formLogin() and logout() methods.

  • Enable Spring MVC Configuration LoginApplicationConfig.java
package com.journaldev.spring.secuity.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;
import org.springframework.web.servlet.view.JstlView;

@EnableWebMvc
@Configuration
@ComponentScan({ "com.journaldev.spring.*" })
@Import(value = { LoginSecurityConfig.class })
public class LoginApplicationConfig {
	@Bean
	public InternalResourceViewResolver viewResolver() {
		InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
		viewResolver.setViewClass(JstlView.class);
		viewResolver.setPrefix("/WEB-INF/views/");
		viewResolver.setSuffix(".jsp");
		return viewResolver;
	}
	
}

Code Explanation:- We use “LoginApplicationConfig” class to define Spring MVC View Resolvers to avoid writing “web.xml” file.

  1. @EnableWebMvc Annotation is used to enable Spring Web MVC Application Features in Spring Framework
  2. @Import Annotation is used to import Spring Security Configuration class into this class.
  3. @ComponentScan Annotation is used to do component scanning in the specified package. It is equal to “context:component-scan” in Spring XML Configuration.
  • Initialize Spring Security
package com.journaldev.spring.secuity.config.core;

import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;

public class SpringSecurityInitializer extends AbstractSecurityWebApplicationInitializer {

}

“SpringSecurityInitializer” is used to register the DelegatingFilterProxy to use the springSecurityFilterChain. It avoids writing Filters configuration in web.xml file.- Initialize Spring MVC Application “SpringMVCWebAppInitializer” class is used to initialize “DispatcherServlet” without web.xml file in a Annotation based configuration. SpringMVCWebAppInitializer.java

package com.journaldev.spring.secuity.config.core;

import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
import com.journaldev.spring.secuity.config.LoginApplicationConfig;

public class SpringMVCWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

	@Override
	protected Class<?>[] getRootConfigClasses() {
		return new Class[] { LoginApplicationConfig.class };
	}

	@Override
	protected Class<?>[] getServletConfigClasses() {
		return null;
	}

	@Override
	protected String[] getServletMappings() {
		return new String[] { "/" };
	}
	
}

NOTE:-

  1. When we access our application, by default SpringMVCWebAppInitializer’s getServletMappings() will allow to access root url: “/”. We can override to forward to a different URL.
  2. The Spring or Pivotal team is working this issue to avoid this much Java code by introduction an annotation. Please check this at https://jira.spring.io/browse/SPR-10359.
  • Develop welcomePage.jsp file
<h3>Welcome to JournalDEV Tutorials</h3>
<a href="${pageContext.request.contextPath}/loginPage">Login to Journal</a>
  • Develop loginPage.jsp file
<%@ taglib prefix="c" uri="https://java.sun.com/jsp/jstl/core"%>
<html>
<body onload='document.loginForm.username.focus();'>
	<h3>JournalDEV Tutorials</h3>

	<c:if test="${not empty error}"><div>${error}</div></c:if>
	<c:if test="${not empty message}"><div>${message}</div></c:if>

	<form name='login' action="<c:url value='/loginPage' />" method='POST'>
		<table>
			<tr>
				<td>UserName:</td>
				<td><input type='text' name='username' value=''></td>
			</tr>
			<tr>
				<td>Password:</td>
				<td><input type='password' name='password' /></td>
			</tr>
			<tr>
				<td colspan='2'><input name="submit" type="submit" value="submit" /></td>
			</tr>
		</table>
		<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />
	</form>
</body>
</html>
  • Develop homepage.jsp file
<%@taglib prefix="c" uri="https://java.sun.com/jsp/jstl/core"%>
<h3>Welcome to JournalDEV Tutorials</h3>
<ul>
	<li>Java 8 tutorial</li>
	<li>Spring tutorial</li>
	<li>Gradle tutorial</li>
	<li>BigData tutorial</li>
</ul>

<c:url value="/logout" var="logoutUrl" />
<form id="logout" action="${logoutUrl}" method="post" >
  <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />
</form>
<c:if test="${pageContext.request.userPrincipal.name != null}">
	<a href="javascript:document.getElementById('logout').submit()">Logout</a>
</c:if>
  • Final Project Structure looks like this: spring security login logout example

Run Spring Security MVC Login Logout Example

To run this Spring Web Application, we need any Web Container which supports Spring 4 and Java 8 Environments With Servlet 3.1.0 Container.

  • Deploy and Run on Spring TC Server in Spring STS Suite
  • It automatically access our application welcome page url as shown below. spring security login example- click on “Login to JournalDEV” link to access login page. spring 4 mvc security login logout example- Now, provide wrong login details and click on “Login” button. spring security login logout Here we can observe this error message: “Invalid Credentials provided.”- Now, provide correct login details configured in “LoginSecurityConfig” class. spring 4 security login After successful login to our application, we can see our Application Homepage with the “Logout” link.- click on “Logout” link to logout from Application. spring security logout example Here we can observe that we are Logged out from our application successfully and redirected to Login page again. We can observe some Log out successful message in this Login page.

NOTE:- If we observe this example, we are not using the web.xml file right. As it is a Web Application, Maven searches for web.xml file and raises some errors if it does not find in the application. That’s to avoid Maven related issues, we need to configure “<failOnMissingWebXml>” flag in pom.xml file. That’s it all about Spring 4 Security Module Simple Example. We will develop some more real-time useful examples in my coming posts like Managing Roles, Remember-Me Feature, WebSocket Security, and more. Please drop me a comment if you like my post or have any issues/suggestions.

Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.

Learn more about our products

About the authors
Default avatar
Pankaj

author

While we believe that this content benefits our community, we have not yet thoroughly reviewed it. If you have any suggestions for improvements, please let us know by clicking the “report an issue“ button at the bottom of the tutorial.

Still looking for an answer?

Ask a questionSearch for more help

Was this helpful?
 
JournalDev
DigitalOcean Employee
DigitalOcean Employee badge
May 19, 2020

Thank so much ! Keep doing

- vu

    JournalDev
    DigitalOcean Employee
    DigitalOcean Employee badge
    October 31, 2019

    Hi Pankaj, Thanks for writing this article, This is a very simple and acute example to understand the Spring security I followed your steps to implement Spring security in one of my existing tutorial project. But I am getting some issues while going to deploy .war file. Could you please check the issue, what it is exactly. I googled it but I couldn’t find the expected result. Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.servlet.Filter]: Factory method ‘springSecurityFilterChain’ threw exception; nested exception is java.lang.NoSuchMethodError: org.springframework.util.Assert.isTrue(ZLjava/util/function/Supplier;)V

    - Devdyuti singh

      JournalDev
      DigitalOcean Employee
      DigitalOcean Employee badge
      September 9, 2018

      Thank You so much. very proper and step by step description gave. Please we want managing different user roles example

      - Akash

        JournalDev
        DigitalOcean Employee
        DigitalOcean Employee badge
        April 3, 2018

        Is it possible to use hashed password instead of plain text in LoginSecurityConfig class, so no one easily guess it?

        - Sumit Sood

          JournalDev
          DigitalOcean Employee
          DigitalOcean Employee badge
          November 20, 2017

          Please help! I am getting following problem: Nov 20, 2017 4:19:02 PM org.springframework.web.servlet.PageNotFound noHandlerFound WARNING: No mapping found for HTTP request with URI [/SpringMVCSecruityMavenApp/${pageContext.request.contextPath}/loginPage] in DispatcherServlet with name ‘dispatcher’

          - Rajesh Gupta

            JournalDev
            DigitalOcean Employee
            DigitalOcean Employee badge
            November 6, 2017

            I am trying to implement Spring Security in my existing Spring MVC project . I have designed my flow like when my application first loads then it goes to “Index.jsp” as below: @RequestMapping(value =“/” , method = RequestMethod.GET) public ModelAndView Index() { System.out.println(“Index”); ModelAndView form = new ModelAndView(“Index”); return form; } And my Index.jsp contains two buttons 1) SignUp and 2) Login . Both this button opens their respective “Modal” on same page . And submits a post request as below : @RequestMapping(value = “/login”, method = RequestMethod.POST) public ModelAndView Login(@RequestParam Map reqvar) { //… //… } @RequestMapping(value = “/signup”, method = RequestMethod.POST) public ModelAndView SignUp(@RequestParam Map reqvar) { //… //… } Now I want to implement Spring Security . How to implement ?? I want some thing that once I submit form from Model for login using {context}/login then Spring should authenticate me for provided userid and password. . So what should I write in " protected void configure(HttpSecurity http) throws Exception {" method ?? As of now I have written some thing like below , but it is not working : @Configuration @EnableWebSecurity public class SpringSecurity extends WebSecurityConfigurerAdapter { public void configureGlobalSecurity(AuthenticationManagerBuilder auth) throws Exception{ auth.inMemoryAuthentication().withUser(“rishavraj3@jellyfish.com”) .password(“123456”).authorities(“ROLE_USER”); } @Override protected void configure(HttpSecurity http) throws Exception { http.csrf().disable(); // disabled csrf as of now for simplicity . http.authorizeRequests().antMatchers(“/login”). access(“hasRole(‘ROLE_USER’)”).and().formLogin().loginPage(“/index”); } }

            - RISHAV

              JournalDev
              DigitalOcean Employee
              DigitalOcean Employee badge
              October 26, 2017

              SIr getting this error The absolute uri: https://java.sun.com/jsp/jstl/core cannot be resolved in either web.xml or the jar files deployed with this application

              - shoaib ali

                JournalDev
                DigitalOcean Employee
                DigitalOcean Employee badge
                October 12, 2017

                Hi Sir, After added correct credentials, getting below error…i have homePage.jsp in place. HTTP Status 404 - /SpringMVCSecruityMavenApp/WEB-INF/views/homePage.jsp -------------------------------------------------------------------------------- type Status report message /SpringMVCSecruityMavenApp/WEB-INF/views/homePage.jsp description The requested resource is not available. -------------------------------------------------------------------------------- Apache Tomcat/7.0.81 Regards

                - Venkata Reddy

                  JournalDev
                  DigitalOcean Employee
                  DigitalOcean Employee badge
                  September 12, 2017

                  Hi, Why is it that when after I login I can still access the login page and it doesn’t redirect to the homePage

                  - Mel

                    JournalDev
                    DigitalOcean Employee
                    DigitalOcean Employee badge
                    July 26, 2017

                    Getting 404 error WARNING: No mapping found for HTTP request with URI [/ex/welcome] in DispatcherServlet with name ‘dispatcher’

                    - Pash

                      Try DigitalOcean for free

                      Click below to sign up and get $200 of credit to try our products over 60 days!

                      Sign up

                      Join the Tech Talk
                      Success! Thank you! Please check your email for further details.

                      Please complete your information!

                      Become a contributor for community

                      Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.

                      DigitalOcean Documentation

                      Full documentation for every DigitalOcean product.

                      Resources for startups and SMBs

                      The Wave has everything you need to know about building a business, from raising funding to marketing your product.

                      Get our newsletter

                      Stay up to date by signing up for DigitalOcean’s Infrastructure as a Newsletter.

                      New accounts only. By submitting your email you agree to our Privacy Policy

                      The developer cloud

                      Scale up as you grow — whether you're running one virtual machine or ten thousand.

                      Get started for free

                      Sign up and get $200 in credit for your first 60 days with DigitalOcean.*

                      *This promotional offer applies to new accounts only.