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.

Spring MVC Security Example using in-memory, UserDetailsService and JDBC Authentication

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:

  • In-Memory Store
  • Relations Databases(RDBMS)
  • No SQL Data Stores
  • 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:

  • Welcome Page
  • Login Page
  • Home Page
  • 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


        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…

  • welcomePage() will handle all client requests which are using “/” URI.
  • homePage() will handle all client requests which are using “/homePage” URI.
  • loginPage() will handle all client requests which are using “/loginPage” URI.

In loginPage(), we have taken 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.security.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.

  • @EnableWebSecurity Annotation is used to enable web security in any web application.
  • @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.

“LoginSecurityConfig” class or any class which is designated to configure Spring Security, should extend “WebSecurityConfigurerAdapter” class or implement related interface.

configureGlobal() method is used to store and mange User Credentials.

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.

Difference between authorities() and roles() methods: 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.

Important method to take care of Login and Logout Security is configure(HttpSecurity http)

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.security.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.

  • @EnableWebMvc Annotation is used to enable Spring Web MVC Application Features in Spring Framework.
  • @Import Annotation is used to import Spring Security Configuration class into this class.
  • @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.security.config.core;

        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.security.config.core;

        import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
        import com.journaldev.spring.security.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: 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. 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:

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 accesses our application welcome page url as shown below.

 

– click on “Login to JournalDEV” link to access login page. Spring 4 MVC

 

– Now, provide wrong login details and click on “Login” button.

 

Here we can observe this error message: “Invalid Credentials provided.” Now, provide correct login details configured in “LoginSecurityConfig” class.

 

After successful login to our application, we can see our Application Homepage with the “Logout” link. click on “Logout” link to logout from Application.

 

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 on Maven and web.xml

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 – a Comprehensive Guide – Today we will learn about Spring Security Login Example

Create a Free Account

Register now and get access to our Cloud Services.

Posts you might be interested in: