Main Tutorials

Spring Security Custom Login Form Annotation Example

In this tutorial, we will convert previous Spring Security custom login form (XML) project to a pure annotation-based project.

Technologies used :

  1. Spring 3.2.8.RELEASE
  2. Spring Security 3.2.3.RELEASE
  3. Eclipse 4.2
  4. JDK 1.6
  5. Maven 3
  6. Tomcat 7 (Servlet 3.x)
Note
In this example, last Spring Security hello world annotation example will be reused, enhance it to support a custom login form.

1. Project Demo

2. Directory Structure

Review the final directory structure of this tutorial.

spring-security-custom-login-annotation-directory

3. Spring Security Configuration

Spring Security configuration via annotations.

SecurityConfig.java

package com.mkyong.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 {

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

	//.csrf() is optional, enabled by default, if using WebSecurityConfigurerAdapter constructor
	@Override
	protected void configure(HttpSecurity http) throws Exception {

	    http.authorizeRequests()
		.antMatchers("/admin/**").access("hasRole('ROLE_USER')")
		.and()
		    .formLogin().loginPage("/login").failureUrl("/login?error")
		    .usernameParameter("username").passwordParameter("password")		
		.and()
		    .logout().logoutSuccessUrl("/login?logout")
		.and()
		    .csrf(); 		
	}
}

The equivalent of the Spring Security XML file :


	<http auto-config="true">
	  <intercept-url pattern="/admin**" access="ROLE_USER" />
	  <form-login 
		login-page="/login" 
	        default-target-url="/welcome" 
		authentication-failure-url="/login?error" 
		username-parameter="username"
		password-parameter="password" />
	  <logout logout-success-url="/login?logout" />
	  <!-- enable csrf protection -->
	  <csrf/>
	</http>

	<authentication-manager>
	  <authentication-provider>
	    <user-service>
		<user name="mkyong" password="123456" authorities="ROLE_USER" />
	    </user-service>
	  </authentication-provider>
	</authentication-manager>

4. Custom Login Form

4.1 Page to display the custom login form. If CSRF protection is enabled, remember to add ${_csrf.token} in both login and logout form.

login.jsp

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html>
<head>
<title>Login Page</title>
<style>
.error {
	padding: 15px;
	margin-bottom: 20px;
	border: 1px solid transparent;
	border-radius: 4px;
	color: #a94442;
	background-color: #f2dede;
	border-color: #ebccd1;
}

.msg {
	padding: 15px;
	margin-bottom: 20px;
	border: 1px solid transparent;
	border-radius: 4px;
	color: #31708f;
	background-color: #d9edf7;
	border-color: #bce8f1;
}

#login-box {
	width: 300px;
	padding: 20px;
	margin: 100px auto;
	background: #fff;
	-webkit-border-radius: 2px;
	-moz-border-radius: 2px;
	border: 1px solid #000;
}
</style>
</head>
<body onload='document.loginForm.username.focus();'>

	<h1>Spring Security Custom Login Form (Annotation)</h1>

	<div id="login-box">

		<h2>Login with Username and Password</h2>

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

		<form name='loginForm'
		    action="<c:url value='j_spring_security_check' />" method='POST'>

		    <table>
			<tr>
				<td>User:</td>
				<td><input type='text' name='user' value=''></td>
			</tr>
			<tr>
				<td>Password:</td>
				<td><input type='password' name='pass' /></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>
	</div>

</body>
</html>

4.2 Page to display the welcome message, default page.

hello.jsp

<%@page session="false"%>
<html>
<body>
	<h1>Title : ${title}</h1>	
	<h1>Message : ${message}</h1>	
</body>
</html>

4.3 This page is password protected, only authenticated user is allowed to access.

admin.jsp + logout

<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@page session="true"%>
<html>
<body>
	<h1>Title : ${title}</h1>
	<h1>Message : ${message}</h1>

	<c:url value="/j_spring_security_logout" var="logoutUrl" />

		<!-- csrt support -->
	<form action="${logoutUrl}" method="post" id="logoutForm">
		<input type="hidden" 
			name="${_csrf.parameterName}"
			value="${_csrf.token}" />
	</form>
	
	<script>
		function formSubmit() {
			document.getElementById("logoutForm").submit();
		}
	</script>

	<c:if test="${pageContext.request.userPrincipal.name != null}">
		<h2>
			Welcome : ${pageContext.request.userPrincipal.name} | <a
				href="javascript:formSubmit()"> Logout</a>
		</h2>
	</c:if>

</body>
</html>

5. Spring MVC Controller

A simple controller.

HelloController.java

package com.mkyong.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 HelloController {

	@RequestMapping(value = { "/", "/welcome**" }, method = RequestMethod.GET)
	public ModelAndView welcomePage() {

		ModelAndView model = new ModelAndView();
		model.addObject("title", "Spring Security Custom Login Form");
		model.addObject("message", "This is welcome page!");
		model.setViewName("hello");
		return model;

	}

	@RequestMapping(value = "/admin**", method = RequestMethod.GET)
	public ModelAndView adminPage() {

		ModelAndView model = new ModelAndView();
		model.addObject("title", "Spring Security Custom Login Form");
		model.addObject("message", "This is protected page!");
		model.setViewName("admin");

		return model;

	}

	//Spring Security see this :
	@RequestMapping(value = "/login", method = RequestMethod.GET)
	public ModelAndView login(
		@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 username and password!");
		}

		if (logout != null) {
			model.addObject("msg", "You've been logged out successfully.");
		}
		model.setViewName("login");

		return model;

	}

}

6. Initializer Classes

Here are the Initializer classes to make this a pure annotation-based project.

6.1 Initializer class to enable the Spring Security configuration.

SpringSecurityInitializer.java

package com.mkyong.config.core;

import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;
public class SpringSecurityInitializer extends AbstractSecurityWebApplicationInitializer {

}

6.2 Initializer class to enable the Spring MVC.

SpringMvcInitializer.java

package com.mkyong.config.core;

import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
import com.mkyong.config.AppConfig;

public class SpringMvcInitializer 
	extends AbstractAnnotationConfigDispatcherServletInitializer {

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

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

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

package com.mkyong.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.mkyong.web.*" })
@Import({ SecurityConfig.class })
public class AppConfig {

	@Bean
	public InternalResourceViewResolver viewResolver() {
		InternalResourceViewResolver viewResolver
                           = new InternalResourceViewResolver();
		viewResolver.setViewClass(JstlView.class);
		viewResolver.setPrefix("/WEB-INF/pages/");
		viewResolver.setSuffix(".jsp");
		return viewResolver;
	}
	
}

7. Demo

7.1. Welcome Page – http://localhost:8080/spring-security-loginform-annotation/

spring-security-custom-login-annotation-welcome

7.2 Try to access /admin page, your custom login form is displayed.

spring-security-custom-login-annotation-login

7.3. If username and password is incorrect, display /login?error.

spring-security-custom-login-annotation-error

7.4. If username and password are correct, Spring will redirect the request to the original requested URL and display the page.

spring-security-custom-login-annotation-admin

7.5. Try to log out, it will redirect to /login?logout page.

spring-security-custom-login-annotation-logout

Download Source Code

References

  1. Spring Security Hello World Annotation Example
  2. Creating a Custom Login Form
  3. Spring Security 3.2.0.RC1 Highlights: CSRF Protection
  4. Wikipedia : Cross-site request forgery

About Author

author image
Founder of Mkyong.com, love Java and open source stuff. Follow him on Twitter. If you like my tutorials, consider make a donation to these charities.

Comments

Subscribe
Notify of
39 Comments
Most Voted
Newest Oldest
Inline Feedbacks
View all comments
vinayak
6 years ago

Hello, How can i integrate spring security in Spring boot rest service and Java Swing(accessing API’s using Apache HttpClient)

FaisalHyder
7 years ago

sorry to say but this is an easy way out… u should have put css and js folders separately inside src/main/resources folder and then have shown how to use them inside our Spring Security application with @EnableWebMVC.

Premnath
9 years ago

When I execute as it is, after entering username and password I am getting below error

HTTP ERROR 403

Problem accessing /login. Reason:

Expected CSRF token not found. Has your session expired?

Ram
6 years ago

Hi

Thanks for the tutorial it was very helpful. But when I use the same configuration in production where I deploy the application in example.com. The redirection when I hit example.com/admin without logging in goes to localhost:8080/login. I understand why this is happening since Spring is running under localhost in the server but is there a way to fix this to redirect to example.com/login instead?

Please note I tried adding baseUrl to loginPage like loginPage(baseUrl + ‘/login’) but that results in infinite loops.

Thanks

shweta chugh
7 years ago

Hi,
I am running two applications UI and UIManager. Both the applications are running at different port. Spring Security is implemented at UIManager application but login page is set in UI application. Spring security works fine in Chrome, but in Mozilla firefox, spring security is not working, Firefox is unable to send a request from UI app to UIManager app. And in IE browser, windows security manager pop up comes after I enter credentials in login page. Please give me the solution to this.

carlos
7 years ago

This solution is BAD, how to use ApplicationEvent with spring security

crewdoo
7 years ago

Hi. How can I get access to _csrf.token if i using freemarker templating engine?

Guna
8 years ago

You have only given the entire program, please also explain as to why we have to use these functions and what does it do..
merely just copying and pasting ur code and running the program is not helping us

Satish Pakalapati
8 years ago

HI Mkyong,

can you please explain below question :

how to prevent multiple users login with same username and password in spring?

Satish Pakalapati
8 years ago

Hi,
can you plz explain below question :

how to prevent multiple users login with same username and password in spring security.

Willians Martins
8 years ago

Hello mkyong, I’m loving your posts, I copy this code tutorial and is running beautiful, but now, I want to use AuthenticationManagerBuilder getting the value of database, I get this code from another your tutorial, When the password is fixed(encrypt) on the database it is ok, but when I try to save in database one another user the password is write without encrypt(plaintext), can you understand me and help me?

yas
8 years ago

This is for those of you who try to learn and make the best of it.

If you are using latest spring security which is “4.0.2.RELEASE”

and if you get blocked by http:xxxx/server_name/context_path/j_spring_security_check

add this to http in SecurityConfig “loginProcessingUrl(“/j_spring_security_check”)” thanks to Denis Ageev

and if you get blocked by http:xxxx/server_name/context_path/j_spring_security_logout

There are two ways possible:

1) .logoutRequestMatcher(new AntPathRequestMatcher(“/j_spring_security_logout”)) in SecurityConfig as the same way you did /j_spring_security_check

2) you put this
insetad of in admin.jsp

this is because of this reason
http://docs.spring.io/spring-security/site/docs/4.0.2.RELEASE/reference/html/jc.html#jc-logout

it says as follow

The URL that triggers log out to occur (default is /logout). If CSRF protection is enabled (default), then the request must also be a POST. For for information, please consult the JavaDoc.

johaness vix
8 years ago

this is not very flexible if you need for example angular js for doing auth besides those html ugly spring tags.

Aspen Sugan
8 years ago

Can anyone please reply me asap.

Jeff
9 years ago

Hello Mr Mkyong

When I run the app on sever (Tomcat), in the browser I get this message “Ressource not available” , and the url is “http://localhost:8002/spring-security-loginform-annotation/”

What’s the problem ?
Please help me. Thank you

PJ
8 years ago
Reply to  Jeff

Check your main console (Tomcat) and check status of your application.

Aman jajodia
6 years ago
Reply to  PJ

I am also facing the same probelm and its just showing servlet startup at the end

akshobhya kallapur
9 years ago

Hi , thanks for this example .. but when I give correct username and password it is going to index page, May I know y?

Guest
9 years ago

Thank you, good tutorial

Nacho
9 years ago

Not working…

Abul Fayes
9 years ago

The username parameter is set as “username” and the password parameter is set as “password” in SecurityConfig.java but in the login.jsp the input fields uses “user” and “pass” for the name attributes so it didn’t work for me without changing the input name attributes to match the parameter values. Otherwise a great tutorial thanks!

Juliuz
9 years ago

Hello, the text for bad credentials and succesful logout isent in colour. Can you help?

Pawel
9 years ago

wery good! It’s really worked!

Priyanka Kulathilaka
9 years ago

I got error and posted here it

[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:2.3.2:compile (default-compile) on project : Compilation failure: Compilation failure:
[ERROR] ..SecurityConfig.java:[12,7] error: cannot access Filter
[ERROR] ..SpringSecurityInitializer.java:[5,7] error: cannot access ServletException
[ERROR] -> [Help 1]

http://stackoverflow.com/questions/25073074/error-cannot-access-filter

Girish
6 years ago

javax.servlet
javax.servlet-api
${javax.servlet.version}
provided

scope is incorrect, it was
provider

Tushar Bhatt
9 years ago

I am not able to deploy the application in Tomcat, on researching I found that there is an error in SecurityConfig.java file. Error is : ”
Could not autowire. No beans of ‘AuthenticationManagerBuilder’ type found.
“. Can somebody help me to resolve the issue.

Virmerson Santos
9 years ago

To function correctly, and avoid 404 error I switched j_spring_security_logout by “/ logout” and also j_spring_security_check by “/ login” in login.jsp file and admin.jsp

Denis Ageev
9 years ago

add this to http in SecurityConfig “loginProcessingUrl(“/j_spring_security_check”)”

RaunakShakya
8 years ago
Reply to  Denis Ageev

thank you. your suggestion helped me solve a problem that had been cracking my brains for the past few days.

Philip Ardley
9 years ago

The ” spring-security-custom-login-form-annotation.zip (19 KB)” can’t be imported to Eclipse ad run on Tomcat 7. These are the steps I took to make the imported (from file system) project work:

1) In the pom.xml change the javax.servlet.version from “3.1.0” to “3.0.1”.
2) In the pom.xml change the jdk.version from “1.6” to “1.7”.
3) Open the project properties, -> Java Build Path -> Libraries, remove all those links to the maven repository.
4) Right click your project, -> Configure -> Convert to maven.
5) Make sure your Tomcat library is in Java Build Path -> Libraries and also is the target runtime.

6) Run the project on the server like normal.

There are very often these types of problems with maven example projects from this website.

Guest
9 years ago

The “last Spring Security hello world annotation example” can’t be imported to Eclipse ad run on Tomcat 7. These are the steps I took to make the imported (from file system) project work:

1) In the pom.xml change the javax.servlet.version from “3.1.0” to “3.0.1”.
2) In the pom.xml change the jdk.version from “1.6” to “1.7”.
3) Open the project properties, -> Java Build Path -> Libraries, remove all those links to the maven repository.
4) Right click your project, -> Configure -> Convert to maven.
5) Make sure your Tomcat library is in Java Build Path -> Libraries and also is the target runtime.

6) Run the project on the server like normal.

There are very often these types of problems with maven example projects from this website.

Lurkin
9 years ago

This tutorial is not working 🙁

I got red mark in eclpse on………..

1.@ComponentScan({ “com.mkyong.web.*” })

2.auth.inMemoryAuthentication().withUser(“mkyong”).password(“123456”).roles(“USER”);

3.AbstractAnnotationConfigDispatcherServletInitializer

4.AbstractSecurityWebApplicationInitializer

The jars I’m using are:

javax.servlet-api-3.0.1.jar

jstl-1.2.jar

org.springframework.context-3.0.4.RELEASE.jar

spring-beans-3.0.4.RELEASE.jar

spring-context-3.0.2.RELEASE.jar

spring-core-3.1.1.RELEASE.jar

spring-security-config-3.2.4.RELEASE.jar

spring-security-core-2.0.2.jar

spring-security-web-3.0.0.RELEASE.jar

spring-web-3.0.5.RELEASE.jar

spring-webmvc-4.0.5.RELEASE.jar

Raghavulu Bussa
9 years ago

Hi,

I’m getting

No mapping found for HTTP request with URI [/{app-context}/j_spring_security_check] in DispatcherServlet with name ‘dispatcher’ when using the java config while it worked with xml config

JukaBarros
9 years ago

If you use Spring Security 3.2.x you should change “j_spring_security_check” to “login” and “j_spring_security_logout” to “logout”

And the parameter (username and password) in SecurityConfig.java must have the same name in input in login.jsp. Example:

SecurityConfig.java

usernameParameter(“name”).passwordParameter(“pass”)

login.jsp

User:

Password:

RiccardoC
9 years ago

as far as I know, this example won’t work with Spring Security 3.2.x; they changed some urls.

j_spring_security_check is now /login (POST only, unless you configure it differently)

you have to provide your mapping for logout, this is is accomplished by something like (after usernameParameter(“username”).passwordParameter(“password”)):

.and().logout().logoutUrl(“/logout”);

Juan Manuel Flores
9 years ago

Same error. Could you make it work?

Bono
9 years ago

I’ve got the same error. Nice example but not working properly.

spring-context, spring-webmvc: 4.0.5.RELEASE
spring-security-core, spring-security-config, spring-security-web: 3.2.4.RELEASE

??????? ???????
9 years ago

Hi, why you don’t use the latest spring 4.

johaness vix
8 years ago

he doesn’t know how to.