Handling duplicate form submission / Post-Redirect-Get Pattern in Spring MVC

In webapp form submission, if you refresh the form success view, most browsers will prompt a pop-up dialog to confirm about the form resubmission. If you click “yes”, the form will be resubmitted again, this scenario is well-known as duplicated form submission.

To avoid this problem, PRG pattern is used, instead of returning a web page directly, the POST operation returns a redirection command. The HTTP 1.1 specification introduced the HTTP 303 response code to ensure that in this situation, the web user’s browser can safely refresh the server response without causing the initial HTTP POST request to be resubmitted.

What is Post-Redirect-Get Pattern?

Post/Redirect/Get (PRG) is a web development design pattern that prevents duplicate form submission. When a web form is submitted to a server through an HTTP POST request, a web user that attempts to refresh the server response in certain user agents can cause the contents of the original HTTP POST request to be resubmitted, possibly causing undesired results, such as a duplicate web purchase.

STEP 1:- Open Eclipse and Create Dynamic Web Project named SpringMVCFormSubmitPRG

STEP 2:- Make sure you use Target Runtime as Apache Tomcat 7.0.

STEP 3:- copy below jars to WEB-INF/lib folder.
  • commons-logging-1.2.jar
  • hibernate-validator-4.3.1.Final.jar
  • jboss-logging-3.1.0.GA.jar
  • spring-aop-4.1.4.RELEASE.jar
  • spring-beans-4.1.4.RELEASE.jar
  • spring-context-4.1.4.RELEASE.jar
  • spring-core-4.1.4.RELEASE.jar
  • spring-expression-4.1.4.RELEASE.jar
  • spring-security-config-4.0.2.RELEASE.jar
  • spring-security-core-4.0.2.RELEASE.jar
  • spring-security-taglibs-4.0.2.RELEASE.jar
  • spring-security-web-4.0.2.RELEASE.jar
  • spring-web-4.1.4.RELEASE.jar
  • spring-webmvc-4.1.4.RELEASE.jar
  • validation-api-1.0.0.GA.jar
STEP 4:- Create Spring Configuration Bean file. /WebContent/WEB-INF/dispatcher-servlet.xml
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:mvc="http://www.springframework.org/schema/mvc" 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/mvc 
 http://www.springframework.org/schema/mvc/spring-mvc.xsd
 http://www.springframework.org/schema/context 
 http://www.springframework.org/schema/context/spring-context.xsd">
 
 <context:component-scan base-package="com.tutorialsdesk.controller" />
 
 <mvc:annotation-driven />
 
 <bean id="viewResolver"
 class="org.springframework.web.servlet.view.UrlBasedViewResolver">
 <property name="viewClass"
 value="org.springframework.web.servlet.view.JstlView" />
 <property name="prefix" value="/WEB-INF/views/" />
 <property name="suffix" value=".jsp" />
 </bean>
 
 <bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
 <property name="basename" value="/WEB-INF/messages" />
 </bean>
 
 <!-- <context:property-placeholder location="/WEB-INF/conf/messages.properties"/> -->
 
</beans>

STEP 5 :- Map Spring configuration files in /WebContent/WEB-INF/web.xml file as below :-
<?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" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0">
 <display-name>SpringMVCFormSubmitPRG</display-name>
 <welcome-file-list>
 <welcome-file>login.html</welcome-file>
 </welcome-file-list>
 <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>*.html</url-pattern>
 </servlet-mapping>
</web-app>

STEP 6 :- create messages.propreties in /WebContent/WEB-INF/ folder as below :-
NotEmpty.userForm.email=Please enter your e-mail. 
Email.userForm.email=Your e-mail is incorrect.

STEP 7 :- Create Model Class.
  • Package: com.tutorialsdesk.model
  • Filename: User.java
package com.tutorialsdesk.model;

import javax.validation.constraints.Size;
import org.hibernate.validator.constraints.Email;
import org.hibernate.validator.constraints.NotEmpty;

public class User {

 @NotEmpty
 @Email
 private String email;
 
 private int token;
 
 @NotEmpty(message = "Please enter your password.")
 @Size(min = 6, max = 15, message = "Your password must between 6 and 15 characters")
 private String password;
 
 public String getEmail() {
 return email;
 }
 
 public void setEmail(String email) {
 this.email = email;
 }
 
 public String getPassword() {
 return password;
 }
 
 public void setPassword(String password) {
 this.password = password;
 }

 public int getToken() {
 return token;
 }

 public void setToken(int token) {
 this.token = token;
 }

}

STEP 8 :- Create Controller Class.
  • Package: com.tutorialsdesk.controller
  • Filename: FormController.java
package com.tutorialsdesk.controller;

import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;

import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import org.springframework.web.servlet.support.RequestContextUtils;
import org.springframework.web.servlet.view.RedirectView;

import com.tutorialsdesk.model.User;

@Controller
public class FormController {
 
 @RequestMapping(value = "/login", method = RequestMethod.GET)
 public String defaultView(HttpServletRequest request, Map<String, Object> model,@ModelAttribute User userForm) {

 Map<String, ?> inputFlashMap = RequestContextUtils.getInputFlashMap(request);

 // A RedirectAttributes model is empty when the method is called and is
 // never used unless the method returns a redirect view name or a
 // RedirectView.
 if (inputFlashMap != null) {
 Boolean hasError = (Boolean) inputFlashMap.get("hasError");
 model.put("userForm", (User)inputFlashMap.get("userForm"));
 if(hasError!=null && Boolean.TRUE){
 return "LoginForm";
 }else{
 return "LoginSuccess";
 }
 }
 else{
 User user = new User();
 model.put("userForm", user);
 return "LoginForm";
 }
 }

 @RequestMapping(value = "/handle", method = RequestMethod.POST)
 public RedirectView handlePost(@Valid @ModelAttribute("userForm") User userForm,
 BindingResult result,HttpServletRequest request, 
 RedirectAttributes redirectAttrs) {
 
 redirectAttrs.addFlashAttribute("userForm",userForm);
 if(result.hasErrors()){
 redirectAttrs.addFlashAttribute("hasError",true);
 redirectAttrs.addFlashAttribute("org.springframework.validation.BindingResult.userForm", result);
 return new RedirectView("/login.html", true);
 }
 return new RedirectView("/login.html", true);
 }
}

STEP 9 :- Create jsp files in /WebContent/WEB-INF/views folder
  • Filename: LoginForm.jsp
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
 
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
 "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Login</title>
<style>
 .error {
 color: red; font-weight: bold;
 }
</style>
</head>
<body>
 <div align="center">
 <h2>Spring MVC Preventing Duplicate Form Submissions using PRG (POST / REDIRECT / GET) Pattern</h2>
 <table border="0" width="90%">
 
 <form:form action="/SpringMVCFormSubmitPRG/handle.html" commandName="userForm">
 <tr>
 <td align="left" width="20%">Email: </td>
 <td align="left" width="40%"><form:input path="email" size="30"/></td>
 <td align="left"><form:errors path="email" cssClass="error"/></td>
 </tr>
 <tr>
 <td>Password: </td>
 <td><form:password path="password" size="30"/></td>
 <td><form:errors path="password" cssClass="error"/></td>
 </tr>
 <tr>
 <td></td>
 <td align="center"><input type="submit" value="Login"/></td>
 <td></td>
 </tr>
 </form:form>
 </table>
 </div>
</body>
</html>

  • Filename: LoginSuccess.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
 pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
 "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Welcome</title>
</head>
<body>
 <div align="center">
 <h2>Welcome ${userForm.email}! You have logged in successfully.</h2>
 </div>
</body>
</html>

STEP 10 :- Run your project enter below URL in your browser

http://localhost:8080/SpringMVCFormSubmitPRG/

Keep visiting TutorialsDesk for more tutorials and practical programming examples on Spring MVC. Hope we are able to explain you Handling duplicate form submission / Post-Redirect-Get Pattern in Spring MVC Example, if you have any questions or suggestions please write to us using contact us form.

Please share us on social media if you like the tutorial.

Spring MVC Security REST Digest Authentication

STEP 1:- Open Eclipse and Create Dynamic Web Project named SpringSecurityRESTDigestAuthentication

STEP 2:- Make sure you use Target Runtime as Apache Tomcat 7.0.

STEP 3:- copy below jars to WEB-INF/lib folder.
  • aopalliance-1.0.jar
  • aspectjrt-1.8.4.jar
  • commons-io-2.4.jar
  • commons-logging-1.2.jar
  • jackson-annotations-2.6.0.jar
  • jackson-core-2.6.0.jar
  • jackson-databind-2.6.0.jar
  • jtds.jar
  • log4j-1.2.17.jar
  • spring-aop-4.1.4.RELEASE.jar
  • spring-beans-4.1.4.RELEASE.jar
  • spring-context-4.1.4.RELEASE.jar
  • spring-core-4.1.4.RELEASE.jar
  • spring-dao-2.0.8.jar
  • spring-expression-4.1.4.RELEASE.jar
  • spring-jdbc-4.1.4.RELEASE.jar
  • spring-security-config-4.0.2.RELEASE.jar
  • spring-security-core-4.0.2.RELEASE.jar
  • spring-security-oauth2-2.0.8.RELEASE.jar
  • spring-security-taglibs-4.0.2.RELEASE.jar
  • spring-security-web-4.0.2.RELEASE.jar
  • spring-web-4.1.4.RELEASE.jar
  • spring-webmvc-4.1.4.RELEASE.jar
STEP 4:- Create Spring Configuration Bean file. /WebContent/WEB-INF/dispatcher-servlet.xml
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:mvc="http://www.springframework.org/schema/mvc" 
 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/mvc 
 http://www.springframework.org/schema/mvc/spring-mvc.xsd
 http://www.springframework.org/schema/context 
 http://www.springframework.org/schema/context/spring-context.xsd">
 <context:component-scan base-package="com.tutorialsdesk.controllers" />
 <context:component-scan base-package="com.tutorialsdesk.services" />

 <mvc:annotation-driven />
 
 <bean id="viewResolver"
 class="org.springframework.web.servlet.view.UrlBasedViewResolver">
 <property name="viewClass"
 value="org.springframework.web.servlet.view.JstlView" />
 <property name="prefix" value="/WEB-INF/views/" />
 <property name="suffix" value=".jsp" />
 </bean>
 
 <bean name="jsonTemplate" class="org.springframework.web.servlet.view.json.MappingJackson2JsonView"/>
</beans>
STEP 5:- Create Spring security configuration file. /WebContent/WEB-INF/spring-security.xml
First thing to understand about the configuration is that, while Spring Security does have full out of the box support for the Digest authentication mechanism, this support is not as well integrated into the namespace as Basic Authentication was.
In this case, we need to manually define the raw beans that are going to make up the security configuration – the DigestAuthenticationFilter and the DigestAuthenticationEntryPoint:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
 xmlns:oauth="http://www.springframework.org/schema/security/oauth2"
 xmlns:security="http://www.springframework.org/schema/security"
 xsi:schemaLocation="http://www.springframework.org/schema/security/oauth2 
 http://www.springframework.org/schema/security/spring-security-oauth2-2.0.xsd
 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">
 
 
<security:global-method-security pre-post-annotations="enabled"/>

 <security:http use-expressions="true" entry-point-ref="digestEntryPoint">
 <security:intercept-url access="hasRole('ROLE_VERIFIED')" pattern="/api/**"/>
 <security:intercept-url pattern='/*' access='permitAll'/>

 <security:logout logout-success-url="/"/>

 <security:session-management session-fixation-protection="newSession">
 <security:concurrency-control max-sessions="1"/>
 </security:session-management>
 
 <security:custom-filter ref="digestFilter" after="BASIC_AUTH_FILTER" />
 </security:http>
 <security:authentication-manager>
 <security:authentication-provider>
 <security:user-service id="userService">
 <security:user name="test" password="test" authorities="ROLE_VERIFIED"/>
 </security:user-service>

 </security:authentication-provider>
 </security:authentication-manager>
 
 
 <bean id="digestFilter" class="org.springframework.security.web.authentication.www.DigestAuthenticationFilter">
 <property name="userDetailsService" ref="userService" />
 <property name="authenticationEntryPoint" ref="digestEntryPoint" />
 </bean>
 
 <bean id="digestEntryPoint" class="org.springframework.security.web.authentication.www.DigestAuthenticationEntryPoint">
 <property name="realmName" value="Contacts Realm via Digest Authentication" />
 <property name="key" value="PrivateKeyValue" />
 <property name="nonceValiditySeconds" value="10"/>
 </bean>
 
</beans>
Next, we need to integrate these beans into the overall security configuration – and in this case, the namespace is still flexible enough to allow us to do that. The first part of this is pointing to the custom entry point bean, via the entry-point-ref attribute of the main <http> element. The second part is adding the newly defined digest filter into the security filter chain. Since this filter is functionally equivalent to the BasicAuthenticationFilter, we are using the same relative position in the chain – this is specified by the BASIC_AUTH_FILTER alias in the overall Spring Security Standard Filters. Finally, notice that the Digest Filter is configured to point to the user service bean – and here, the namespace is again very useful as it allows us to specify a bean name for the default user service created by the <user-service> element:
<user-service id="userService">
STEP 6 :- Map Spring configuration files in /WebContent/WEB-INF/web.xml file as below :-
<?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" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
 <display-name>SpringSecurityRESTDigestAuthentication</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>
 <listener>
 <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
 </listener>
 <context-param>
 <param-name>contextConfigLocation</param-name>
 <param-value> 
 /WEB-INF/spring-security.xml
 </param-value>
 </context-param>
 <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>

STEP 7 :- Create Controller Class.
  • Package: com.tutorialsdesk.controller
  • Filename: RestController.java
package com.tutorialsdesk.controllers;

import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
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.bind.annotation.ResponseBody;

import com.tutorialsdesk.models.Employee;
import com.tutorialsdesk.services.EmployeeService;

@Controller
@RequestMapping()
public class RestController {

 @Autowired
 EmployeeService employeeService;

 @RequestMapping(value = "api/users", method = RequestMethod.GET)
 @ResponseBody
 public List<Employee> list() {
 System.out.println("RestController.list()");
 
 return employeeService.getEmployeesList();
 }
 
}

STEP 9 :- Create Model Class.
  • Package: com.tutorialsdesk.model
  • Filename: Employee.java
package com.tutorialsdesk.models;

import java.io.Serializable;

public class Employee implements Serializable{

 private static final long serialVersionUID = 5088863992478607917L;

 private Integer id;
 
 private String firstName;

 private String lastName;
 
 private String email;

 public Employee(Integer id, String firstName, String lastName, String email) {
 super();
 this.id = id;
 this.firstName = firstName;
 this.lastName = lastName;
 this.email = email;
 }

 public Employee() {
 super();
 }

 public Integer getId() {
 return id;
 }

 public void setId(Integer id) {
 this.id = id;
 }

 public String getFirstName() {
 return firstName;
 }

 public void setFirstName(String firstName) {
 this.firstName = firstName;
 }

 public String getLastName() {
 return lastName;
 }

 public void setLastName(String lastName) {
 this.lastName = lastName;
 }

 public String getEmail() {
 return email;
 }

 public void setEmail(String email) {
 this.email = email;
 }

 public static long getSerialversionuid() {
 return serialVersionUID;
 }

 @Override
 public String toString() {
 return "Employee [id=" + id + ", firstName=" + firstName
 + ", lastName=" + lastName + ", email=" + email + "]";
 }
 
}

STEP 10 :- Create Service Interface and Class.
  • Package: com.tutorialsdesk.services
  • Filename: EmployeeService.java
package com.tutorialsdesk.services;

import java.util.List;

import com.tutorialsdesk.models.Employee;

public interface EmployeeService {
 public List<Employee> getEmployeesList();
}

  • Package: com.tutorialsdesk.services
  • Filename: EmployeeServiceImpl.java
package com.tutorialsdesk.services;

import java.util.ArrayList;
import java.util.List;

import org.springframework.stereotype.Service;

import com.tutorialsdesk.models.Employee;

@Service
public class EmployeeServiceImpl implements EmployeeService {

 @Override
 public List<Employee> getEmployeesList() {
 List<Employee> employeeList = new ArrayList<Employee>();
 employeeList.add(new Employee(1, "Prince", "Sethi", "prince@gmail.com"));
 employeeList.add(new Employee(2, "Rambir", "Singh", "rambir@gmail.com"));
 employeeList.add(new Employee(3, "Vishnu", "Jangid", "vishnu@gmail.com"));
 return employeeList;
 }

}

STEP 11 :- Create jsp file in /WebContent/WEB-INF folder
  • Filename: index.jsp
<html>
<body>
<h2>Spring REST Security Digest Authentication</h2> 
<a href="http://localhost:8080/SpringSecurityRESTDigestAuthentication/api/users">Get Users List</a>
<br/>
<br/>
Or use CURL command <br/>
<br/>
curl -i --digest --user test:test http://localhost:8080/SpringSecurityRESTDigestAuthentication/api/users

</body>
</html>

STEP 12 :- Run your project enter below URL in your browser http://localhost:8080/SpringSecurityRESTDigestAuthentication/ STEP 13 :- Consuming The Secured Application The curl command is our go to tool for consuming the secured application.
First, let’s try to request the /api/users without providing any security credentials:
curl -i http://localhost:8080/SpringSecurityRESTDigestAuthentication/api/users

We get back the expected 401 Unauthorized and the Authentication Challenge:
HTTP/1.1 401 Unauthorized
Server: Apache-Coyote/1.1
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-XSS-Protection: 1; mode=block
X-Frame-Options: DENY
X-Content-Type-Options: nosniff
Set-Cookie: JSESSIONID=B8B4177EE54D239C35B4A4EE36EAD2C2; Path=/SpringSecurityRES
TDigestAuthentication/; HttpOnly
WWW-Authenticate: Digest realm="Contacts Realm via Digest Authentication", qop="
auth", nonce="MTQ2Njc1MTMyMTM0NDo2NDQ3Zjc2ODc1MWQ0MThmMzM5ZWNiMGZlZGNkMDYzNQ=="
Content-Type: text/html;charset=utf-8
Content-Language: en
Content-Length: 1061
Date: Fri, 24 Jun 2016 06:55:11 GMT

<html><head><title>Apache Tomcat/7.0.55 - Error report</title><style><!--H1 {fon
t-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:
22px;} H2 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525
D76;font-size:16px;} H3 {font-family:Tahoma,Arial,sans-serif;color:white;backgro
und-color:#525D76;font-size:14px;} BODY {font-family:Tahoma,Arial,sans-serif;col
or:black;background-color:white;} B {font-family:Tahoma,Arial,sans-serif;color:w
hite;background-color:#525D76;} P {font-family:Tahoma,Arial,sans-serif;backgroun
d:white;color:black;font-size:12px;}A {color : black;}A.name {color : black;}HR
{color : #525D76;}--></style> </head><body><h1>HTTP Status 401 - Full authentica
tion is required to access this resource</h1><HR size="1" noshade="noshade"><p><
b>type</b> Status report</p><p><b>message</b> <u>Full authentication is required
 to access this resource</u></p><p><b>description</b> <u>This request requires H
TTP authentication.</u></p><HR size="1" noshade="noshade"><h3>Apache Tomcat/7.0.
55</h3></body></html>

The browser would interpret this challenge and prompt us for credentials with a simple dialog, but since we’re using curl, this isn’t the case.

Let’s now provide the correct credentials and send the request again:
curl -i --digest --user test:test http://localhost:8080/SpringSecurityRESTDigestAuthentication/api/users

Notice that we are enabling Digest Authentication for the curl command via the –digest flag. The first response from the server will be the same – the 401 Unauthorized – but the challenge will now be interpreted and acted upon by a second request – which will succeed with a 200 OK:
HTTP/1.1 401 Unauthorized
Server: Apache-Coyote/1.1
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-XSS-Protection: 1; mode=block
X-Frame-Options: DENY
X-Content-Type-Options: nosniff
Set-Cookie: JSESSIONID=4A34FF7C29FC9702D5A7F986D5815429; Path=/SpringSecurityRES
TDigestAuthentication/; HttpOnly
WWW-Authenticate: Digest realm="Contacts Realm via Digest Authentication", qop="
auth", nonce="MTQ2Njc1MTM3NDgwMzoxYTJmZTNiMWRjZDAyNTUxY2EyYjM0MWQ3NzE4M2E4ZA=="
Content-Type: text/html;charset=utf-8
Content-Language: en
Content-Length: 1061
Date: Fri, 24 Jun 2016 06:56:04 GMT

HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-XSS-Protection: 1; mode=block
X-Frame-Options: DENY
X-Content-Type-Options: nosniff
Set-Cookie: JSESSIONID=5CD390094F262230FBB6EA59E1253846; Path=/SpringSecurityRES
TDigestAuthentication/; HttpOnly
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Fri, 24 Jun 2016 06:56:04 GMT

[{"id":1,"firstName":"Prince","lastName":"Sethi","email":"prince@gmail.com"},{"i
d":2,"firstName":"Rambir","lastName":"Singh","email":"rambir@gmail.com"},{"id":3
,"firstName":"Vishnu","lastName":"Jangid","email":"vishnu@gmail.com"}]
From the browser, the application can be consumed normally – the only difference is that a login page is no longer a hard requirement since all browsers support Basic Authentication and use a dialog to prompt the user for credentials.

A final note on this interaction is that a client can preemptively send the correct Authorization header with the first request, and thus entirely avoid the server security challenge and the second request.

Keep visiting TutorialsDesk for more tutorials and practical programming examples on Spring MVC. Hope we are able to explain you Spring MVC Security REST Digest Authentication Example, if you have any questions or suggestions please write to us using contact us form.

Please share us on social media if you like the tutorial.

Spring MVC Security REST Basic Authentication

STEP 1:- Open Eclipse and Create Dynamic Web Project named SpringSecurityRESTBasicAuthentication

STEP 2:- Make sure you use Target Runtime as Apache Tomcat 7.0.

STEP 3:- copy below jars to WEB-INF/lib folder.
  • aopalliance-1.0.jar
  • aspectjrt-1.8.4.jar
  • commons-io-2.4.jar
  • commons-logging-1.2.jar
  • jackson-annotations-2.6.0.jar
  • jackson-core-2.6.0.jar
  • jackson-databind-2.6.0.jar
  • jtds.jar
  • log4j-1.2.17.jar
  • spring-aop-4.1.4.RELEASE.jar
  • spring-beans-4.1.4.RELEASE.jar
  • spring-context-4.1.4.RELEASE.jar
  • spring-core-4.1.4.RELEASE.jar
  • spring-dao-2.0.8.jar
  • spring-expression-4.1.4.RELEASE.jar
  • spring-jdbc-4.1.4.RELEASE.jar
  • spring-security-config-4.0.2.RELEASE.jar
  • spring-security-core-4.0.2.RELEASE.jar
  • spring-security-oauth2-2.0.8.RELEASE.jar
  • spring-security-taglibs-4.0.2.RELEASE.jar
  • spring-security-web-4.0.2.RELEASE.jar
  • spring-web-4.1.4.RELEASE.jar
  • spring-webmvc-4.1.4.RELEASE.jar
STEP 4:- Create Spring Configuration Bean file. /WebContent/WEB-INF/dispatcher-servlet.xml
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:mvc="http://www.springframework.org/schema/mvc" 
 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/mvc 
 http://www.springframework.org/schema/mvc/spring-mvc.xsd
 http://www.springframework.org/schema/context 
 http://www.springframework.org/schema/context/spring-context.xsd">
 
 <context:component-scan base-package="com.tutorialsdesk.controllers" />
 <context:component-scan base-package="com.tutorialsdesk.services" />
 
 <mvc:annotation-driven />
 
 <bean id="viewResolver"
 class="org.springframework.web.servlet.view.UrlBasedViewResolver">
 <property name="viewClass"
 value="org.springframework.web.servlet.view.JstlView" />
 <property name="prefix" value="/WEB-INF/views/" />
 <property name="suffix" value=".jsp" />
 </bean>
 
 <bean name="jsonTemplate" class="org.springframework.web.servlet.view.json.MappingJackson2JsonView"/>
</beans>
STEP 5:- Create Spring security configuration file. /WebContent/WEB-INF/spring-security.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
 xmlns:oauth="http://www.springframework.org/schema/security/oauth2"
 xmlns:security="http://www.springframework.org/schema/security"
 xsi:schemaLocation="http://www.springframework.org/schema/security/oauth2 
 http://www.springframework.org/schema/security/spring-security-oauth2-2.0.xsd
 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">
 
 
<security:global-method-security pre-post-annotations="enabled"/>

 <security:http use-expressions="true">
 <security:intercept-url access="hasRole('ROLE_VERIFIED')" pattern="/api/**"/>
 <security:intercept-url pattern='/*' access='permitAll'/>

 <security:logout logout-success-url="/"/>

 <security:session-management session-fixation-protection="newSession">
 <security:concurrency-control max-sessions="1"/>
 </security:session-management>

 <security:http-basic />
 </security:http>
 <security:authentication-manager>
 <security:authentication-provider>
 <security:user-service>
 <security:user name="test" password="test" authorities="ROLE_VERIFIED"/>
 </security:user-service>

 </security:authentication-provider>
 </security:authentication-manager>
</beans>

What is relevant here is the <http-basic> element inside the main <http> element of the configuration – this is enough to enable Basic Authentication for the entire application.
The Authentication Manager is not the focus of this tutorial, so we are using an in memory manager with the user and password defined in plaintext.

STEP 6 :- Map Spring configuration files in /WebContent/WEB-INF/web.xml file as below :-
<?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" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
 <display-name>SpringSecurityRESTBasicAuthentication</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>
 <listener>
 <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
 </listener>
 <context-param>
 <param-name>contextConfigLocation</param-name>
 <param-value> 
 /WEB-INF/spring-security.xml
 </param-value>
 </context-param>
 <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>

STEP 7 :- Create Controller Class.
  • Package: com.tutorialsdesk.controller
  • Filename: RestController.java
package com.tutorialsdesk.controllers;

import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
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.bind.annotation.ResponseBody;

import com.tutorialsdesk.models.Employee;
import com.tutorialsdesk.services.EmployeeService;

@Controller
@RequestMapping()
public class RestController {

 @Autowired
 EmployeeService employeeService;

 @RequestMapping(value = "api/users", method = RequestMethod.GET)
 @ResponseBody
 public List<Employee> list() {
 System.out.println("RestController.list()");
 
 return employeeService.getEmployeesList();
 }
 
}

STEP 9 :- Create Model Class.
  • Package: com.tutorialsdesk.model
  • Filename: Employee.java
package com.tutorialsdesk.models;

import java.io.Serializable;

public class Employee implements Serializable{

 private static final long serialVersionUID = 5088863992478607917L;

 private Integer id;
 
 private String firstName;

 private String lastName;
 
 private String email;

 public Employee(Integer id, String firstName, String lastName, String email) {
 super();
 this.id = id;
 this.firstName = firstName;
 this.lastName = lastName;
 this.email = email;
 }

 public Employee() {
 super();
 }

 public Integer getId() {
 return id;
 }

 public void setId(Integer id) {
 this.id = id;
 }

 public String getFirstName() {
 return firstName;
 }

 public void setFirstName(String firstName) {
 this.firstName = firstName;
 }

 public String getLastName() {
 return lastName;
 }

 public void setLastName(String lastName) {
 this.lastName = lastName;
 }

 public String getEmail() {
 return email;
 }

 public void setEmail(String email) {
 this.email = email;
 }

 public static long getSerialversionuid() {
 return serialVersionUID;
 }

 @Override
 public String toString() {
 return "Employee [id=" + id + ", firstName=" + firstName
 + ", lastName=" + lastName + ", email=" + email + "]";
 }
 
}

STEP 10 :- Create Service Interface and Class.
  • Package: com.tutorialsdesk.services
  • Filename: EmployeeService.java
package com.tutorialsdesk.services;

import java.util.List;

import com.tutorialsdesk.models.Employee;

public interface EmployeeService {
 public List<Employee> getEmployeesList();
}

  • Package: com.tutorialsdesk.services
  • Filename: EmployeeServiceImpl.java
package com.tutorialsdesk.services;

import java.util.ArrayList;
import java.util.List;

import org.springframework.stereotype.Service;

import com.tutorialsdesk.models.Employee;

@Service
public class EmployeeServiceImpl implements EmployeeService {

 @Override
 public List<Employee> getEmployeesList() {
 List<Employee> employeeList = new ArrayList<Employee>();
 employeeList.add(new Employee(1, "Prince", "Sethi", "prince@gmail.com"));
 employeeList.add(new Employee(2, "Rambir", "Singh", "rambir@gmail.com"));
 employeeList.add(new Employee(3, "Vishnu", "Jangid", "vishnu@gmail.com"));
 return employeeList;
 }

}

STEP 11 :- Create jsp file in /WebContent/WEB-INF folder
  • Filename: index.jsp
<html>
<body>
<h2>Spring REST Security Basic Authentication</h2> 
<a href="http://localhost:8080/SpringSecurityRESTBasicAuthentication/api/users">Get Users List</a>
<br/>
<br/>
Or use CURL command <br/>
<br/>
curl -i --user test:test http://localhost:8080/SpringSecurityRESTBasicAuthentication/api/users

</body>
</html>

STEP 12 :- Run your project enter below URL in your browser

http://localhost:8080/SpringSecurityRESTBasicAuthentication/

STEP 13 :- Consuming The Secured Application The curl command is our go to tool for consuming the secured application.
First, let’s try to request the /api/users without providing any security credentials:
curl -i http://localhost:8080/SpringSecurityRESTBasicAuthentication/api/users

We get back the expected 401 Unauthorized and the Authentication Challenge:
HTTP/1.1 401 Unauthorized
Server: Apache-Coyote/1.1
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-XSS-Protection: 1; mode=block
X-Frame-Options: DENY
X-Content-Type-Options: nosniff
Set-Cookie: JSESSIONID=D3E07DD1EE9DA030C14C958CF207D5A2; Path=/SpringSecurityRES
TBasicAuthentication/; HttpOnly
WWW-Authenticate: Basic realm="Spring Security Application"
Content-Type: text/html;charset=utf-8
Content-Language: en
Content-Length: 1061
Date: Fri, 24 Jun 2016 06:17:52 GMT

<html><head><title>Apache Tomcat/7.0.55 - Error report</title><style><!--H1 {fon
t-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:
22px;} H2 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525
D76;font-size:16px;} H3 {font-family:Tahoma,Arial,sans-serif;color:white;backgro
und-color:#525D76;font-size:14px;} BODY {font-family:Tahoma,Arial,sans-serif;col
or:black;background-color:white;} B {font-family:Tahoma,Arial,sans-serif;color:w
hite;background-color:#525D76;} P {font-family:Tahoma,Arial,sans-serif;backgroun
d:white;color:black;font-size:12px;}A {color : black;}A.name {color : black;}HR
{color : #525D76;}--></style> </head><body><h1>HTTP Status 401 - Full authentica
tion is required to access this resource</h1><HR size="1" noshade="noshade"><p><
b>type</b> Status report</p><p><b>message</b> <u>Full authentication is required
 to access this resource</u></p><p><b>description</b> <u>This request requires H
TTP authentication.</u></p><HR size="1" noshade="noshade"><h3>Apache Tomcat/7.0.
55</h3></body></html>

The browser would interpret this challenge and prompt us for credentials with a simple dialog, but since we’re using curl, this isn’t the case.

Now, let’s request the same resource – /api/users – but provide the credentials to access it as well:
curl -i --user test:test http://localhost:8080/SpringSecurityRESTBasicAuthentication/api/users

Now, the response from the server is 200 OK along with a Cookie:
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-XSS-Protection: 1; mode=block
X-Frame-Options: DENY
X-Content-Type-Options: nosniff
Set-Cookie: JSESSIONID=299E6E6B73DB9E94E4AAC0AD01F7F258; Path=/SpringSecurityRES
TBasicAuthentication/; HttpOnly
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Fri, 24 Jun 2016 06:19:25 GMT

[{"id":1,"firstName":"Prince","lastName":"Sethi","email":"prince@gmail.com"},{"i
d":2,"firstName":"Rambir","lastName":"Singh","email":"rambir@gmail.com"},{"id":3
,"firstName":"Vishnu","lastName":"Jangid","email":"vishnu@gmail.com"}]

From the browser, the application can be consumed normally – the only difference is that a login page is no longer a hard requirement since all browsers support Basic Authentication and use a dialog to prompt the user for credentials.

STEP 14 :- Further Configuration – The Entry Point By default, the BasicAuthenticationEntryPoint provisioned by Spring Security returns a full html page for a 401 Unauthorized response back to the client. This html representation of the error renders well in a browser, but it not well suited for other scenarios, such as a REST API where a json representation may be preferred. The namespace is flexible enough for this new requirement as well – to address this – the entry point can be overridden:
<security:http-basic entry-point-ref="customAuthenticationEntryPoint" />

The new entry point is defined as a standard bean:
  • Package: com.tutorialsdesk.security
  • Filename: CustomAuthenticationEntryPoint.java
package com.tutorialsdesk.security;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint;
import org.springframework.stereotype.Component;

@Component
public class CustomAuthenticationEntryPoint extends BasicAuthenticationEntryPoint{

 @Override
 public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authEx) throws IOException, ServletException {
 response.addHeader("WWW-Authenticate", "Basic realm=" + getRealmName() + "");
 response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
 PrintWriter writer = response.getWriter();
 writer.println("HTTP Status 401 - " + authEx.getMessage());
 }
 
 @Override
 public void afterPropertiesSet() throws Exception {
 setRealmName("Baeldung");
 super.afterPropertiesSet();
 }
 
}
By writing directly to the HTTP Response we now have full control over the format of the response body. Keep visiting TutorialsDesk for more tutorials and practical programming examples on Spring MVC. Hope we are able to explain you Spring MVC Security REST Basic Authentication Example, if you have any questions or suggestions please write to us using contact us form.

Please share us on social media if you like the tutorial.

Spring MVC security limit login attempts example using Java configuration

STEP 1:- To perform database authentication, you have to create tables to store the users and roles detail. Here are the MySQL scripts to create users and user_roles tables.
  • Table: users
CREATE  TABLE users (
  username VARCHAR(60) NOT NULL ,
  password VARCHAR(60) NOT NULL ,
  enabled TINYINT NOT NULL DEFAULT 1 ,
  accountNonExpired TINYINT NOT NULL DEFAULT 1 ,
  accountNonLocked TINYINT NOT NULL DEFAULT 1 ,
  credentialsNonExpired TINYINT NOT NULL DEFAULT 1 ,
  PRIMARY KEY (username));

  • Table: user_roles
CREATE TABLE user_roles (
  user_role_id int(11) NOT NULL AUTO_INCREMENT,
  username varchar(60) NOT NULL,
  role varchar(60) NOT NULL,
  PRIMARY KEY (user_role_id),
  UNIQUE KEY uni_username_role (role,username),
  KEY fk_username_idx (username),
  CONSTRAINT fk_username FOREIGN KEY (username) REFERENCES users (username));


  • Table: user_attempts
CREATE TABLE user_attempts (
  id int(11) NOT NULL AUTO_INCREMENT,
  username varchar(45) NOT NULL,
  attempts varchar(45) NOT NULL,
  lastModified datetime NOT NULL,
  PRIMARY KEY (id)
);


  • here is insert script
insert into users values('user','123456',1)
insert into users values('apiuser','123456',1)
insert into users values('admin','123456',1)

insert into user_roles values('user','ROLE_USER')
insert into user_roles values('admin','ROLE_USER')
insert into user_roles values('admin','ROLE_ADMIN')
insert into user_roles values('admin','ROLE_API')
insert into user_roles values('apiuser','ROLE_USER')
insert into user_roles values('apiuser','ROLE_API')

STEP 2:- Open Eclipse and Create Dynamic Web Project named SpringSecurityLimitLoginAttemptJavaConfig

STEP 3:- Make sure you use Target Runtime as Apache Tomcat 7.0 and Dynamic web module version as 3.0..

STEP 4:- copy below jars to WEB-INF/lib folder.
  • antlr-2.7.6.jar
  • aopalliance-1.0.jar
  • commons-logging-1.2.jar
  • dom4j-1.6.1.jar
  • hibernate-commons-annotations-4.0.4.Final.jar
  • hibernate-core-4.3.6.Final.jar
  • hibernate-jpa-2.1-api-1.0.0.Final.jar
  • hibernate-validator-4.3.2.Final.jar
  • javassist-3.12.1.GA.jar
  • jboss-logging-3.1.0.CR1.jar
  • jta.jar
  • jtds.jar
  • persistence-api-1.0.2.jar
  • spring-aop-4.1.4.RELEASE.jar
  • spring-aspects-4.1.4.RELEASE.jar
  • spring-beans-4.1.4.RELEASE.jar
  • spring-context-4.1.4.RELEASE.jar
  • spring-core-4.1.4.RELEASE.jar
  • spring-expression-4.1.4.RELEASE.jar
  • spring-jdbc-4.1.4.RELEASE.jar
  • spring-orm-4.1.4.RELEASE.jar
  • spring-security-config-4.0.2.RELEASE.jar
  • spring-security-core-4.0.2.RELEASE.jar
  • spring-security-taglibs-4.0.2.RELEASE.jar
  • spring-security-web-4.0.2.RELEASE.jar
  • spring-tx-4.1.4.RELEASE.jar
  • spring-web-4.1.4.RELEASE.jar
  • spring-webmvc-4.1.4.RELEASE.jar
STEP 5:- Create Spring DataSource configuration file.
  • Package: com.tutorialsdesk.config
  • Filename: DataSourceConfig.java
package com.tutorialsdesk.config;

import java.util.Properties;

import javax.annotation.Resource;
import javax.sql.DataSource;

import org.hibernate.SessionFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.hibernate4.HibernateTransactionManager;
import org.springframework.orm.hibernate4.LocalSessionFactoryBuilder;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@Configuration
@EnableTransactionManagement
public class DataSourceConfig {

 private static final String PROPERTY_NAME_DATABASE_DRIVER = "db.driver";
 private static final String PROPERTY_NAME_DATABASE_PASSWORD = "db.password";
 private static final String PROPERTY_NAME_DATABASE_URL = "db.jdbcurl";
 private static final String PROPERTY_NAME_DATABASE_USERNAME = "db.username";

 @Resource
 private Environment env;
 
 @Bean
 public DataSource dataSource() {
 DriverManagerDataSource dataSource = new DriverManagerDataSource();
 dataSource.setDriverClassName(env.getRequiredProperty(PROPERTY_NAME_DATABASE_DRIVER));
 dataSource.setUrl(env.getRequiredProperty(PROPERTY_NAME_DATABASE_URL));
 dataSource.setUsername(env.getRequiredProperty(PROPERTY_NAME_DATABASE_USERNAME));
 dataSource.setPassword(env.getRequiredProperty(PROPERTY_NAME_DATABASE_PASSWORD));
 
 return dataSource;
 }
 
 @Bean
 public SessionFactory sessionFactory() {
 LocalSessionFactoryBuilder builder = new LocalSessionFactoryBuilder(dataSource());
 builder.scanPackages("com.tutorialsdesk.model").addProperties(getHibernateProperties());

 return builder.buildSessionFactory();
 }
 
 private Properties getHibernateProperties() {
 Properties prop = new Properties();
 prop.put("hibernate.format_sql", "true");
 prop.put("hibernate.show_sql", "true");
 prop.put("hibernate.connection.pool_size", "5");
 prop.put("hibernate.hbm2ddl.auto", "update");
 prop.put("hibernate.dialect", "org.hibernate.dialect.SQLServerDialect");
 return prop;
 }
 
 @Bean
 public HibernateTransactionManager transactionManager() {
 return new HibernateTransactionManager(sessionFactory());
 }
 
}

STEP 6:- Create db.properties file under WEB-INF/db.properties.
db.driver=com.mysql.jdbc.Driver
db.jdbcurl=jdbc:mysql://localhost:3306/test
db.username=root
db.password=password

STEP 7:- Create Spring Security configuration fileas below.
  • Package: com.tutorialsdesk.config
  • Filename: SecurityConfig.java
package com.tutorialsdesk.config;

import java.util.ArrayList;
import java.util.List;

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.ProviderManager;
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;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import com.tutorialsdesk.service.CustomUsernamePasswordAuthenticationFilter;

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
 
 @Autowired
 private DataSource dataSource;
 
 @Autowired
 @Qualifier("authenticationProvider")
 AuthenticationProvider authenticationProvider;
 
 @Autowired
 public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
 auth.authenticationProvider(authenticationProvider);
 }

 @Override
 protected void configure(HttpSecurity http) throws Exception {

 http.authorizeRequests()
 .antMatchers("/").permitAll()
 .antMatchers("/home").access("hasRole('ROLE_USER')")
 .antMatchers("/admin/**").access("hasRole('ROLE_ADMIN')")
 .antMatchers("/api/**").access("hasRole('ROLE_ADMIN') or hasRole('ROLE_API')")
 .and()
 .formLogin()
 .loginProcessingUrl("/login")
 .loginPage("/loginPage")
 .failureUrl("/loginPage?error")
 .defaultSuccessUrl("/home")
 .usernameParameter("username")
 .passwordParameter("password")
 .and()
 .exceptionHandling()
 .accessDeniedPage("/Access_Denied");
 
 
 }
 
}
STEP 8:- Create a class extends AbstractSecurityWebApplicationInitializer, it will load the springSecurityFilterChain automatically.
  • Package: com.tutorialsdesk.config.core
  • Filename: SpringSecurityInitializer.java
package com.tutorialsdesk.config.core;

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

public class SpringSecurityInitializer extends
 AbstractSecurityWebApplicationInitializer {

}
STEP 9:- Create Spring MVC configuration file. A Config class, define the view’s technology and imports above DataSourceConfig and SecurityConfig.
  • Package: com.tutorialsdesk.config
  • Filename: WebMvcConfig.java
package com.tutorialsdesk.config;

import javax.annotation.Resource;

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.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
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.tutorialsdesk.controller","com.tutorialsdesk.service","com.tutorialsdesk.dao.impl","com.tutorialsdesk.service.impl","com.tutorialsdesk.handler" })
@Import({ SecurityConfig.class, DataSourceConfig.class })
@PropertySource("/WEB-INF/db.properties")
public class WebMvcConfig {

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

STEP 10:- Create a Sevlet Initializer class, to load everything.
  • Package: com.tutorialsdesk.config.core
  • Filename: SpringMvcInitializer.java
package com.tutorialsdesk.config.core;

import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

import com.tutorialsdesk.config.AppConfig;

public class SpringMvcInitializer extends
 AbstractAnnotationConfigDispatcherServletInitializer {

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

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

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

}

STEP 11 :- Create Controller Class.
  • Package: com.tutorialsdesk.controller
  • Filename: HelloWorldController.java
package com.tutorialsdesk.controller;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.LockedException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
import org.springframework.stereotype.Controller;
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 org.springframework.web.bind.annotation.RequestParam;

@Controller
public class HelloWorldController {

 @RequestMapping(value = { "/", "/loginPage" }, method = RequestMethod.GET)
 public String loginPage(ModelMap model, @RequestParam(value = "error", required = false) String error, HttpServletRequest request) {
 
 if (error != null) {
 model.addAttribute("error", getErrorMessage(request, "SPRING_SECURITY_LAST_EXCEPTION"));
 }
 return "login";
 }
 
 @RequestMapping(value = { "/home" }, method = RequestMethod.GET)
 public String homePage(ModelMap model) {
 
 model.addAttribute("greeting", "Hi, Welcome to mysite. ");
 return "welcome";
 }

 @RequestMapping(value = "/admin", method = RequestMethod.GET)
 public String adminPage(ModelMap model) {
 model.addAttribute("user", getPrincipal());
 return "admin";
 }
 
 @RequestMapping(value = "/api", method = RequestMethod.GET)
 public String dbaPage(ModelMap model) {
 model.addAttribute("user", getPrincipal());
 return "api";
 }
 
 
 @RequestMapping(value="/logout", method = RequestMethod.GET)
 public String logoutPage (ModelMap model,HttpServletRequest request, HttpServletResponse response) {
 Authentication auth = SecurityContextHolder.getContext().getAuthentication();
 if (auth != null){ 
 new SecurityContextLogoutHandler().logout(request, response, auth);
 }
 model.addAttribute("msg", "You've been logged out successfully.");
 return "login";
 }
 
 @RequestMapping(value = "/Access_Denied", method = RequestMethod.GET)
 public String accessDeniedPage(ModelMap model) {
 model.addAttribute("user", getPrincipal());
 return "accessDenied";
 }
 
 private String getPrincipal(){
 String userName = null;
 Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
 
 if (principal instanceof UserDetails) {
 userName = ((UserDetails)principal).getUsername();
 } else {
 userName = principal.toString();
 }
 return userName;
 }
 
 private String getErrorMessage(HttpServletRequest request, String key){
 
 Exception exception = (Exception) request.getSession().getAttribute(key);
 
 String error = "";
 if (exception instanceof BadCredentialsException) {
 error = "Invalid username and password!";
 }else if(exception instanceof LockedException) {
 error = exception.getMessage();
 }else{
 error = "Invalid username and password!";
 }
 
 return error;
 }
 
}

STEP 12 :- Create Model Class.
  • Package: com.tutorialsdesk.model
  • Filename: User.java
package com.tutorialsdesk.model;

import java.util.HashSet;
import java.util.Set;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;

@Entity
@Table(name = "users")
public class User {

 private String username;
 private String password;
 private boolean enabled;
 private boolean accountNonExpired;
 private boolean accountNonLocked;
 private boolean credentialsNonExpired;
 
 private Set<UserRole> userRole = new HashSet<UserRole>(0);

 public User() {
 }

 public User(String username, String password, boolean enabled) {
 this.username = username;
 this.password = password;
 this.enabled = enabled;
 }

 public User(String username, String password, 
 boolean enabled, Set<UserRole> userRole) {
 this.username = username;
 this.password = password;
 this.enabled = enabled;
 this.userRole = userRole;
 }

 @Id
 @Column(name = "username", unique = true, 
 nullable = false, length = 45)
 public String getUsername() {
 return this.username;
 }

 public void setUsername(String username) {
 this.username = username;
 }

 @Column(name = "password", 
 nullable = false, length = 60)
 public String getPassword() {
 return this.password;
 }

 public void setPassword(String password) {
 this.password = password;
 }

 @Column(name = "enabled", nullable = false)
 public boolean isEnabled() {
 return this.enabled;
 }

 public void setEnabled(boolean enabled) {
 this.enabled = enabled;
 }

 
 @Column(name = "accountNonExpired", nullable = false)
 public boolean isAccountNonExpired() {
 return accountNonExpired;
 }

 public void setAccountNonExpired(boolean accountNonExpired) {
 this.accountNonExpired = accountNonExpired;
 }

 @Column(name = "accountNonLocked", nullable = false)
 public boolean isAccountNonLocked() {
 return accountNonLocked;
 }

 public void setAccountNonLocked(boolean accountNonLocked) {
 this.accountNonLocked = accountNonLocked;
 }

 @Column(name = "credentialsNonExpired", nullable = false)
 public boolean isCredentialsNonExpired() {
 return credentialsNonExpired;
 }

 public void setCredentialsNonExpired(boolean credentialsNonExpired) {
 this.credentialsNonExpired = credentialsNonExpired;
 }

 @OneToMany(fetch = FetchType.EAGER, mappedBy = "user")
 public Set<UserRole> getUserRole() {
 return this.userRole;
 }

 public void setUserRole(Set<UserRole> userRole) {
 this.userRole = userRole;
 }

}

  • Package: com.tutorialsdesk.model
  • Filename: UserRole.java
package com.tutorialsdesk.model;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;

import org.hibernate.annotations.GenericGenerator;

@Entity
@Table(name = "user_roles", uniqueConstraints = @UniqueConstraint(columnNames = { "role", "username" }))
public class UserRole {

 private Integer userRoleId;
 private User user;
 private String role;

 public UserRole() {
 }

 public UserRole(User user, String role) {
 this.user = user;
 this.role = role;
 }

 @Id
 @GenericGenerator(name="native", strategy = "native") 
 @GeneratedValue(generator = "native")
 @Column(name = "user_role_id", unique = true, nullable = false)
 public Integer getUserRoleId() {
 return this.userRoleId;
 }

 public void setUserRoleId(Integer userRoleId) {
 this.userRoleId = userRoleId;
 }

 @ManyToOne(fetch = FetchType.LAZY)
 @JoinColumn(name = "username", nullable = false)
 public User getUser() {
 return this.user;
 }

 public void setUser(User user) {
 this.user = user;
 }

 @Column(name = "role", nullable = false, length = 45)
 public String getRole() {
 return this.role;
 }

 public void setRole(String role) {
 this.role = role;
 }
 
}

  • Package: com.tutorialsdesk.model
  • Filename: UserAttempts.java
package com.tutorialsdesk.model;

import java.util.Date;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

import org.hibernate.annotations.GenericGenerator;

@Entity
@Table(name = "user_attempts")
public class UserAttempts {

 @Id
 @GenericGenerator(name="native", strategy = "native") 
 @GeneratedValue(generator = "native")
 @Column(name = "id")
 private int id;
 
 @Column(name = "username", unique = true, nullable = false, length = 60)
 private String username;
 
 @Column(name = "attempts", unique = true, nullable = false, length = 60)
 private int attempts;
 
 @Column(name = "lastModified")
 @Temporal(TemporalType.TIMESTAMP)
 private Date lastModified;

 public UserAttempts() {
 
 }

 public UserAttempts(String username, int attempts, Date lastModified) {
 super();
 this.username = username;
 this.attempts = attempts;
 this.lastModified = lastModified;
 }

 public int getId() {
 return id;
 }

 public void setId(int id) {
 this.id = id;
 }

 public String getUsername() {
 return username;
 }

 public void setUsername(String username) {
 this.username = username;
 }

 public int getAttempts() {
 return attempts;
 }

 public void setAttempts(int attempts) {
 this.attempts = attempts;
 }

 public Date getLastModified() {
 return lastModified;
 }

 public void setLastModified(Date lastModified) {
 this.lastModified = lastModified;
 }

 
}

STEP 13 :- Create Service Interface and Class.
  • Package: com.tutorialsdesk.service
  • Filename: UserService.java
package com.tutorialsdesk.service;

import com.tutorialsdesk.model.User;
import com.tutorialsdesk.model.UserAttempts;

public interface UserService {

 public User findUserByName(String username);
 void updateFailAttempts(String username);
 void resetFailAttempts(String username);
 public UserAttempts getUserAttempts(String username);
}

  • Package: com.tutorialsdesk.service.impl
  • Filename: UserServiceImpl.java
package com.tutorialsdesk.service.impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.tutorialsdesk.dao.UserDao;
import com.tutorialsdesk.model.User;
import com.tutorialsdesk.model.UserAttempts;
import com.tutorialsdesk.service.UserService;

@Service("userService")
@Transactional
public class UserServiceImpl implements UserService {

 @Autowired
 private UserDao userDao;
 
 @Override
 public User findUserByName(String username) {
 return userDao.findUserByName(username);
 }

 @Override
 public void updateFailAttempts(String username) {
 userDao.updateFailAttempts(username);
 
 }

 @Override
 public void resetFailAttempts(String username) {
 userDao.resetFailAttempts(username);
 
 }

 @Override
 public UserAttempts getUserAttempts(String username) {
 
 return userDao.getUserAttempts(username);
 }

}

STEP 14 :- Create Dao Interface and Class.
  • Package: com.tutorialsdesk.dao
  • Filename: UserDao.java
package com.tutorialsdesk.dao;

import com.tutorialsdesk.model.User;
import com.tutorialsdesk.model.UserAttempts;

public interface UserDao {

 public User findUserByName(String username);
 void updateFailAttempts(String username);
 void resetFailAttempts(String username);
 public UserAttempts getUserAttempts(String username);
}
  • Package: com.tutorialsdesk.dao.impl
  • Filename: UserDaoImpl.java
package com.tutorialsdesk.dao.impl;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.LockedException;
import org.springframework.stereotype.Repository;

import com.tutorialsdesk.dao.UserDao;
import com.tutorialsdesk.model.User;
import com.tutorialsdesk.model.UserAttempts;

@Repository("userDao")
public class UserDaoImpl implements UserDao {

 @Autowired
 private SessionFactory sessionFactory;
 
 private static final int MAX_ATTEMPTS = 3;
 
 @SuppressWarnings("unchecked")
 @Override
 public User findUserByName(String username) {
 List<User> userList = new ArrayList<User>();
 
 userList = sessionFactory.getCurrentSession().createQuery("from User where username=?").setParameter(0, username).list();

 if (userList.size() > 0)
 return userList.get(0);
 else
 return null;

 
 }

 @Override
 public void updateFailAttempts(String username) {
 UserAttempts userAttempts = getUserAttempts(username);
 
 if(userAttempts!=null){ 
 User user = findUserByName(username);
 if(user!=null){
 Session s = sessionFactory.openSession();
 Transaction t = s.beginTransaction();
 Query query = s.createQuery("UPDATE UserAttempts SET attempts=:attempts, lastModified=:lastModified WHERE id=:id");
 query.setParameter("attempts", userAttempts.getAttempts() + 1);
 query.setParameter("lastModified", new Date());
 query.setParameter("id", userAttempts.getId());
 query.executeUpdate();
 t.commit();
 
 }
 
 if(userAttempts.getAttempts() >= MAX_ATTEMPTS){
 Session s = sessionFactory.openSession();
 Transaction t = s.beginTransaction();
 Query query = s.createQuery("UPDATE User SET accountNonLocked=:accountNonLocked WHERE username=:username");
 query.setParameter("accountNonLocked", false);
 query.setParameter("username", username);
 query.executeUpdate();
 t.commit();
 throw new LockedException("User Account is locked!");
 }
 
 }
 else{
 User user = findUserByName(username);
 if(user!=null){
 System.out.println("UserDaoImpl.updateFailAttempts()");
 UserAttempts ua = new UserAttempts(username, 1, new Date());
 sessionFactory.getCurrentSession().save(ua);
 }
 }
 
 
 }

 @Override
 public void resetFailAttempts(String username) {
 UserAttempts userAttempts = getUserAttempts(username);
 if(userAttempts!=null){ 
 UserAttempts ua = (UserAttempts) sessionFactory.getCurrentSession().load(UserAttempts.class, userAttempts.getId());
 ua.setAttempts(0);
 ua.setLastModified(new Date());
 }
 
 
 
 }

 
 @Override
 public UserAttempts getUserAttempts(String username) {
 List<UserAttempts> userAttemptsList = new ArrayList<UserAttempts>();
 
 userAttemptsList = sessionFactory.getCurrentSession().createQuery("from UserAttempts where username=?").setParameter(0, username).list();

 if (userAttemptsList.size() > 0)
 return userAttemptsList.get(0);
 else
 return null;
 }

}

STEP 15 :- Create Custom UserDetailsService Class.
  • Package: com.tutorialsdesk.service
  • Filename: CustomUserDetailsService.java
package com.tutorialsdesk.service;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.tutorialsdesk.model.UserRole;

@Service("customUserDetailsService")
public class CustomUserDetailsService implements UserDetailsService {

 @Autowired
 private UserService userService;
 
 @Transactional(readOnly=true)
 @Override
 public UserDetails loadUserByUsername(final String username) 
 throws UsernameNotFoundException {

 com.tutorialsdesk.model.User user = userService.findUserByName(username);
 List<GrantedAuthority> authorities = buildUserAuthority(user.getUserRole());

 return buildUserForAuthentication(user, authorities);
 
 }

 // Converts com.tutorialsdesk.model.User user to
 // org.springframework.security.core.userdetails.User
 private User buildUserForAuthentication(com.tutorialsdesk.model.User user, 
 List<GrantedAuthority> authorities) {
 
 // boolean enabled = true;
 boolean accountNotExpired = true;
 boolean credentialsNotExpired = true;
 // boolean accountNotLocked = true;
 
 return new User(user.getUsername(), user.getPassword(), 
 user.isEnabled(), accountNotExpired, credentialsNotExpired, user.isAccountNonLocked(), authorities);
 }

 private List<GrantedAuthority> buildUserAuthority(Set<UserRole> userRoles) {

 Set<GrantedAuthority> setAuths = new HashSet<GrantedAuthority>();

 // Build user's authorities
 for (UserRole userRole : userRoles) {
 setAuths.add(new SimpleGrantedAuthority(userRole.getRole()));
 }

 List<GrantedAuthority> Result = new ArrayList<GrantedAuthority>(setAuths);

 return Result;
 }
 
}
STEP 16 :- Create Custom User Authentication Handler Class.
  • Package: com.tutorialsdesk.handler
  • Filename: LimitLoginAuthenticationProvider.java
package com.tutorialsdesk.handler;

import java.util.Date;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.LockedException;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.stereotype.Component;

import com.tutorialsdesk.model.UserAttempts;
import com.tutorialsdesk.service.UserService;

@Component("authenticationProvider")
public class LimitLoginAuthenticationProvider extends DaoAuthenticationProvider {

 @Autowired 
 private UserService userService;
 
 @Autowired
 @Qualifier("customUserDetailsService")
 @Override
 public void setUserDetailsService(UserDetailsService userDetailsService) {
 super.setUserDetailsService(userDetailsService);
 }
 
 @Override
 public Authentication authenticate(Authentication authentication) 
 throws AuthenticationException {

 try {

 Authentication auth = super.authenticate(authentication);
 
 
 //if reach here, means login success, else an exception will be thrown
 //reset the user_attempts
 userService.resetFailAttempts(authentication.getName());
 
 return auth;
 
 } catch (BadCredentialsException e) { 
 
 //invalid login, update to user_attempts
 userService.updateFailAttempts(authentication.getName());
 throw e;
 
 } catch (LockedException e){
 
 //this user is locked!
 String error = "";
 UserAttempts userAttempts = userService.getUserAttempts(authentication.getName());
 if(userAttempts!=null){
 Date lastAttempts = userAttempts.getLastModified();
 error = "User account is locked! <br><br>Username : " + authentication.getName() + "<br>Last Attempts : " + lastAttempts;
 }else{
 error = e.getMessage();
 }
 
 throw new LockedException(error);
 }

 }
 
}
STEP 17 :- Create jsp files in /WebContent/WEB-INF/views folder
  • Filename: login.jsp
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@page session="true"%>
<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 Login Form (Limit Login Attempts)</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='/login' />" method='POST'>

 <table>
 <tr>
 <td>User:</td>
 <td><input type='text' name='username'></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="language"
 value="EN" />
 <input type="hidden" name="${_csrf.parameterName}"
 value="${_csrf.token}" />

 </form>
 </div>

</body>
</html>

  • Filename: welcome.jsp
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html>
<head>
 <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
 <title>HelloWorld page</title>
</head>
<body>
 Greeting : ${greeting}
 This is a welcome page.
 <a href="<c:url value="/logout" />">Logout</a>
 <br/>
 <br/>
 <br/>
<a href="<c:url value="/admin" />">Admin Page</a> ( Only Admin user can access this )
<br/>
<br/>
<a href="<c:url value="/api" />">API Page</a> ( Admin or API user can access this )

</body>
</html>

  • Filename: admin.jsp
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html>
<head>
 <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
 <title>HelloWorld Admin page</title>
</head>
<body>
 Dear <strong>${user}</strong>, Welcome to Admin Page.
 <a href="<c:url value="/home" />">Home </a> | 
 <a href="<c:url value="/logout" />"> Logout</a>
</body>
</html>

  • Filename: api.jsp
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html>
<head>
 <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
 <title>DBA page</title>
</head>
<body>
 Dear <strong>${user}</strong>, Welcome to API Page.
 <a href="<c:url value="/home" />">Home </a> | 
 <a href="<c:url value="/logout" />"> Logout</a>
</body>
</html>

  • Filename: accessDenied.jsp
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html>
<head>
<title>AccessDenied page</title>
<style>
.error {
 padding: 15px;
 margin-bottom: 20px;
 border: 1px solid transparent;
 border-radius: 4px;
 color: #a94442;
 background-color: #f2dede;
 border-color: #ebccd1;
}
</style>
</head>
<body>
 Dear <strong>${user}</strong>, 
 <br/>
 <br/>
 
 <div class="error">You are not authorized to access this page.</div>
 <br/>
 <br/>
 <a href="<c:url value="/home" />">Home </a> | 
 <a href="<c:url value="/logout" />"> Logout</a>
</body>
</html>

STEP 18 :- Run your project enter below URL in your browser

http://localhost:8080/SpringSecurityLimitLoginAttemptJavaConfig/

Keep visiting TutorialsDesk for more tutorials and practical programming examples on Spring MVC. Hope we are able to explain you Spring MVC security limit login attempts example using Java configuration Example, if you have any questions or suggestions please write to us using contact us form.

Please share us on social media if you like the tutorial.

Spring MVC role based login example

To allow role based login and redirection we will user custom success handler in spring security.

STEP 1:- Open Eclipse and Create Dynamic Web Project named SpringSecurityRoleBasedLogin 

STEP 2:- Make sure you use Target Runtime as Apache Tomcat 7.0.

STEP 3:- copy below jars to WEB-INF/lib folder.
  • antlr-2.7.6.jar
  • aopalliance-1.0.jar
  • commons-logging-1.2.jar
  • dom4j-1.6.1.jar
  • hibernate-commons-annotations-4.0.4.Final.jar
  • hibernate-core-4.3.6.Final.jar
  • hibernate-jpa-2.1-api-1.0.0.Final.jar
  • hibernate-validator-4.3.2.Final.jar
  • javassist-3.12.1.GA.jar
  • jboss-logging-3.1.0.CR1.jar
  • jta.jar
  • jtds.jar
  • persistence-api-1.0.2.jar
  • spring-aop-4.1.4.RELEASE.jar
  • spring-aspects-4.1.4.RELEASE.jar
  • spring-beans-4.1.4.RELEASE.jar
  • spring-context-4.1.4.RELEASE.jar
  • spring-core-4.1.4.RELEASE.jar
  • spring-expression-4.1.4.RELEASE.jar
  • spring-jdbc-4.1.4.RELEASE.jar
  • spring-orm-4.1.4.RELEASE.jar
  • spring-security-config-4.0.2.RELEASE.jar
  • spring-security-core-4.0.2.RELEASE.jar
  • spring-security-taglibs-4.0.2.RELEASE.jar
  • spring-security-web-4.0.2.RELEASE.jar
  • spring-tx-4.1.4.RELEASE.jar
  • spring-web-4.1.4.RELEASE.jar
  • spring-webmvc-4.1.4.RELEASE.jar
STEP 4: you can use our Spring Hibernate integration post in order to continue with this. STEP 6 :- Create Custom Success Handler Class.
  • Package: com.tutorialsdesk.security.service
  • Filename: CustomSuccessHandler.java
package com.tutorialsdesk.security.service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.web.DefaultRedirectStrategy;
import org.springframework.security.web.RedirectStrategy;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
import org.springframework.stereotype.Component;

@Component
public class CustomSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {

 private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
 
 @Override
 protected void handle(HttpServletRequest request, 
 HttpServletResponse response, Authentication authentication) throws IOException {
 String targetUrl = determineTargetUrl(authentication);
 
 if (response.isCommitted()) {
 System.out.println("Can't redirect");
 return;
 }
 
 redirectStrategy.sendRedirect(request, response, targetUrl);
 }
 
 protected String determineTargetUrl(Authentication authentication) {
 String url="";
 
 Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
 
 List<String> roles = new ArrayList<String>();
 
 for (GrantedAuthority a : authorities) {
 roles.add(a.getAuthority());
 }
 
 if (isDba(roles)) {
 url = "/api";
 } else if (isAdmin(roles)) {
 url = "/admin";
 } else if (isUser(roles)) {
 url = "/home";
 } else {
 url="/Access_Denied";
 }
 
 return url;
 }
 
 public void setRedirectStrategy(RedirectStrategy redirectStrategy) {
 this.redirectStrategy = redirectStrategy;
 }
 protected RedirectStrategy getRedirectStrategy() {
 return redirectStrategy;
 }
 
 private boolean isUser(List<String> roles) {
 if (roles.contains("ROLE_USER")) {
 return true;
 }
 return false;
 }
 
 private boolean isAdmin(List<String> roles) {
 if (roles.contains("ROLE_ADMIN")) {
 return true;
 }
 return false;
 }
 
 private boolean isDba(List<String> roles) {
 if (roles.contains("ROLE_API")) {
 return true;
 }
 return false;
 }
}
STEP 5 :- Modify spring-security.xml to use customSuccessHandler.
<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="/" access="permitAll" />
 
 <intercept-url pattern="/home" access="permitAll" />
 
 <intercept-url pattern="/admin**" access="hasRole('ADMIN')" />
 
 <!-- <intercept-url pattern="/api**" access="hasRole('ADMIN') and hasRole('API')" /> -->
 
 <intercept-url pattern="/api**" access="hasRole('ADMIN') or hasRole('API')" />
 
 <!-- access denied page -->
 <access-denied-handler error-page="/Access_Denied" />
 
 <form-login 
 login-processing-url="/login"
 login-page="/login" 
 username-parameter="username"
 password-parameter="password"
 authentication-success-handler-ref="customSuccessHandler"
 authentication-failure-url="/login?error"/>
 <!-- enable csrf protection -->
 <csrf/>
 
 </http>
 
 <!-- Select users and user_roles from database -->
 <authentication-manager >
 <authentication-provider user-service-ref="customUserDetailsService"/>
 </authentication-manager>
 
 <beans:bean id="customUserDetailsService" class="com.tutorialsdesk.security.service.CustomUserDetailsService" />
 <beans:bean id="customSuccessHandler" class="com.tutorialsdesk.security.service.CustomSuccessHandler" />
 
</beans:beans>

STEP 6 :- Run your project enter below URL in your browser

http://localhost:8080/SpringSecurityRoleBasedLogin/

Keep visiting TutorialsDesk for more tutorials and practical programming examples on Spring MVC. Hope we are able to explain you Spring MVC role based login Example, if you have any questions or suggestions please write to us using contact us form.

Please share us on social media if you like the tutorial.

Spring MVC Security Password Encryption

In this tutorial, we will show you how to use BCryptPasswordEncoder to hash a password and perform a login authentication in Spring Security.

STEP 1 : Generate a BCrypt Password First, hash a password and put it into a database or in spring security in memory config, for login authentication later. This example uses BCryptPasswordEncoder to hash a password “123456”.
  • Filename: PasswordEncoderGenerator.java
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

public class PasswordEncoderGenerator {

 public static void main(String[] args) {

 int i = 0;
 while (i < 5) {
 String password = "123456";
 BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
 String hashedPassword = passwordEncoder.encode(password);

 System.out.println(hashedPassword);
 i++;
 }

 }
}

In BCrypt hashing algorithm, each time, a different hash value of length 60 is generated.
$2a$10$bVVGBTJW.eotUJvxeZkEEuop69ZEuhFAyLBIBS9KGC2xwITVYVwGi
$2a$10$afgx66/oURNEx5upfSM4k.hQjzng7u3dIzwWV3QQbNr.hdaegjv7e
$2a$10$kzym7WgzynrB8fSaAhbCJOaWlQH8sPPmehfWZ.PlKUYQEj2qTTqUS
$2a$10$umqihmMYnVqlKgVch5En8emTlYjfFcedXgXHZELoqOcxIBjoc89Qq
$2a$10$EUaXUkipS1x2j2o738hJMOs3rhfwI03J6UFtgWmtK53Zu0zL8Ny5.

It's normal to get a different value each time you hash a value with BCrypt, because salt is generated randomly. In this tutorial, we get the first output and use it. STEP 2 : Enable Password Encoder A few ways to enable the password encoder in XML configuration. Using the default BCryptPasswordEncoder.

Spring Security In Memory Authentication

add below to your spring-security.xml
    

<authentication-manager >
 <authentication-provider>
 
 <user-service>
 <user name="user" password="123456" authorities="ROLE_USER" />
 <user name="admin" password="$2a$10$J77YiMP1/U05eXaSr1XhQumEpO57yI9NugROQnUBJ5xUWPjc2V9Xy" authorities="ROLE_ADMIN,ROLE_API" />
 <user name="apiuser" password="$2a$10$J77YiMP1/U05eXaSr1XhQumEpO57yI9NugROQnUBJ5xUWPjc2V9Xy" authorities="ROLE_API" />
 </user-service>
 <password-encoder ref="encoder" /> 
 </authentication-provider>
 </authentication-manager>
 
 
 <beans:bean id="encoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"> 
 <beans:constructor-arg name="strength" value="10" /> 
 </beans:bean>

Spring Security DB Authentication

add below to your spring-security.xml
    

<!-- Select users and user_roles from database -->
 <authentication-manager>
 <authentication-provider>
 <jdbc-user-service data-source-ref="dataSource"
 users-by-username-query=
 "select username,password, enabled from users where username=?"
 authorities-by-username-query=
 "select username, role from user_roles where username =? " />
 <password-encoder ref="encoder" /> 
 </authentication-provider>
 </authentication-manager>
 
 
 <beans:bean id="encoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"> 
 <beans:constructor-arg name="strength" value="10" /> 
 </beans:bean>

Spring Security Hibernate Authentication

add below to your spring-security.xml
 
   
<!-- Select users and user_roles from database -->
 <authentication-manager >
 <authentication-provider user-service-ref="customUserDetailsService">
 <password-encoder ref="encoder" />
 </authentication-provider>
 </authentication-manager>
 
 <beans:bean id="customUserDetailsService" class="com.tutorialsdesk.service.CustomUserDetailsService" />
 
 <beans:bean id="encoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"> 
 <beans:constructor-arg name="strength" value="10" /> 
 </beans:bean>

In case of db / Hibernate authentication you need to store encrypted password in password field of user table. Keep visiting TutorialsDesk for more tutorials and practical programming examples on Spring MVC. Hope we are able to explain you Spring MVC Security Password Encryption example, if you have any questions or suggestions please write to us using contact us form.

Please share us on social media if you like the tutorial.

Spring MVC Security @PreFilter and @PostFilter annotations

@PreFilter and @PostFilter are designated to use with Spring security to be able to filter collections or arrays based on the authorization.

To have this working, you need to use expression-based access control in spring security

@PreFilter - filters the collection or arrays before executing method.

@PostFilter - filters the returned collection or arrays after executing the method.

Spring security provides a built-in object named as filterObject at which @PreFilter and @PostFilter performs filtering task. @PreFilter and @PostFilter can be used on service layer with @PreAuthorize and @PostAuthorize. Use interface to declare the filter operation.

STEP 1:- Open Eclipse and Create Dynamic Web Project named SpringSecurityFilterAnnotation

STEP 2:- Make sure you use Target Runtime as Apache Tomcat 7.0. STEP 3:- copy below jars to WEB-INF/lib folder.
  • aopalliance-1.0.jar
  • commons-logging-1.2.jar
  • spring-aop-4.1.4.RELEASE.jar
  • spring-beans-4.1.4.RELEASE.jar
  • spring-context-4.1.4.RELEASE.jar
  • spring-core-4.1.4.RELEASE.jar
  • spring-expression-4.1.4.RELEASE.jar
  • spring-security-config-4.0.2.RELEASE.jar
  • spring-security-core-4.0.2.RELEASE.jar
  • spring-security-taglibs-4.0.2.RELEASE.jar
  • spring-security-web-4.0.2.RELEASE.jar
  • spring-web-4.1.4.RELEASE.jar
  • spring-webmvc-4.1.4.RELEASE.jar
STEP 4:- Create Spring Configuration Bean file. /WebContent/WEB-INF/dispatcher-servlet.xml
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:mvc="http://www.springframework.org/schema/mvc" 
 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/mvc 
 http://www.springframework.org/schema/mvc/spring-mvc.xsd
 http://www.springframework.org/schema/context 
 http://www.springframework.org/schema/context/spring-context.xsd">
 
 <context:component-scan base-package="com.tutorialsdesk.controller" />
 
 <bean id="viewResolver"
 class="org.springframework.web.servlet.view.UrlBasedViewResolver">
 <property name="viewClass"
 value="org.springframework.web.servlet.view.JstlView" />
 <property name="prefix" value="/WEB-INF/views/" />
 <property name="suffix" value=".jsp" />
 </bean>
 <mvc:annotation-driven/>
</beans>

STEP 5:- Create Spring security configuration file. /WebContent/WEB-INF/spring-security.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="/home" access="hasAnyRole('ROLE_READ','ROLE_WRITE','ROLE_NONE')" />
<!-- access denied page-->
 <access-denied-handler error-page="/Access_Denied" />
 
 <form-login 
 login-processing-url="/login"
 login-page="/login" 
 default-target-url="/home" 
 username-parameter="username"
 password-parameter="password"
 authentication-failure-url="/login?error"/> 
 
 </http>
 
 <authentication-manager >
 <authentication-provider>
 <user-service>
 <user name="superman" password="123456" authorities="ROLE_READ,ROLE_WRITE" />
 <user name="spiderman" password="123456" authorities="ROLE_READ" />
 <user name="user" password="123456" authorities="ROLE_NONE" />
 </user-service>
 </authentication-provider>
 </authentication-manager>
 
 <!-- <global-method-security secured-annotations="enabled"/> -->
 <global-method-security pre-post-annotations="enabled"/>
 
 <beans:bean id="customService" class="com.tutorialsdesk.service.CustomServiceImpl" />
 
</beans:beans>

In order to enable Spring Method level Security, we need to add <global-method-security pre-post-annotations="enabled"/> in security context file, as shown above.

STEP 6 :- Map Spring configuration files in /WebContent/WEB-INF/web.xml file as below :-
<?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" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0">
 <display-name>SpringSecurityFilterAnnotation</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/spring-security.xml
 </param-value>
 </context-param>
 <listener>
 <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
 </listener>
 <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>

STEP 7 :- Create Model Class.
  • Package: com.tutorialsdesk.model
  • Filename: Folder.java
package com.tutorialsdesk.model;

public class Folder {

 private String folderName;
 private String owner;
 public Folder(String folderName, String owner) {
 super();
 this.folderName = folderName;
 this.owner = owner;
 }
 public String getFolderName() {
 return folderName;
 }
 public void setFolderName(String folderName) {
 this.folderName = folderName;
 }
 public String getOwner() {
 return owner;
 }
 public void setOwner(String owner) {
 this.owner = owner;
 }
}

STEP 8 :- Create Service Interface.
  • Package: com.tutorialsdesk.service
  • Filename: CustomService.java
package com.tutorialsdesk.service;

import java.util.List;

import org.springframework.security.access.prepost.PostFilter;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.access.prepost.PreFilter;

import com.tutorialsdesk.model.Folder;

public interface CustomService {
 
 @PreAuthorize ("hasRole('ROLE_READ')")
 @PostFilter ("filterObject.owner == authentication.name")
 public List<Folder> getFolders();
 
 @PreFilter("filterObject.owner == authentication.name")
 public void addFolder(List<Folder> folders);
}

filterObject is built-in object on which filter operation is performed. In this declaration, for the first method getFolders() we have used @PreAuthorize and @PostFilter. Before executing method, user is authorized on the basis of role and then after executing, the returned object is filtered on the basis of owner. Second method addFolder() is only using @PreFilter on the basis of owner

STEP 9 :- Create Service Impl Class.
  • Package: com.tutorialsdesk.service
  • Filename: CustomServiceImpl.java
package com.tutorialsdesk.service;

import java.util.ArrayList;
import java.util.List;

import org.springframework.stereotype.Service;

import com.tutorialsdesk.model.Folder;

@Service
public class CustomServiceImpl implements CustomService {

 @Override
 public List<Folder> getFolders() {
 
 List<Folder> folders = new ArrayList<Folder>();
 folders.add(new Folder("ABC","superman"));
 folders.add(new Folder("XYZ","spiderman"));
 folders.add(new Folder("JKL","spiderman"));
 folders.add(new Folder("MNP","superman"));
 
 return folders;
 }

 @Override
 public void addFolder(List<Folder> folders) {
 System.out.println("Folders Added.");
 for(Folder f: folders){
 System.out.println(f.getFolderName()+":"+f.getOwner());
 }
 
 }

}

STEP 10 :- Create Controller Class.
  • Package: com.tutorialsdesk.controller
  • Filename: IndexController.java
package com.tutorialsdesk.controller;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.annotation.Secured;
import org.springframework.security.access.prepost.PostAuthorize;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

import com.tutorialsdesk.model.Folder;
import com.tutorialsdesk.service.CustomService;

@Controller
public class IndexController {

 @Autowired
 private CustomService customService;
 
 @RequestMapping(value = {"/", "/login" }, method = RequestMethod.GET)
 public String loginPage(ModelMap model, @RequestParam(value = "error", required = false) String error) {
 
 if (error != null) {
 model.addAttribute("error", "Invalid username and password!");
 }
 return "login";
 }
 
 @RequestMapping(value = { "/home" }, method = RequestMethod.GET)
 public String homePage(ModelMap model) {

 List<Folder> folders = new ArrayList<Folder>();
 folders.add(new Folder("ABC","superman"));
 folders.add(new Folder("XYZ","spiderman"));
 folders.add(new Folder("JKL","spiderman"));
 folders.add(new Folder("MNP","superman"));
 
 if(hasRole("ROLE_WRITE")){
 customService.addFolder(folders);
 }
 if(hasRole("ROLE_READ")){
 List<Folder> foldersList = customService.getFolders();
 System.out.println("Folders we got.");
 for(Folder f: foldersList){
 System.out.println(f.getFolderName()+":"+f.getOwner());
 }
 }
 model.addAttribute("msg", "Done Successfully");
 
 return "welcome";
 }
 
 
 @RequestMapping(value="/logout", method = RequestMethod.GET)
 public String logoutPage (ModelMap model,HttpServletRequest request, HttpServletResponse response) {
 Authentication auth = SecurityContextHolder.getContext().getAuthentication();
 if (auth != null){ 
 new SecurityContextLogoutHandler().logout(request, response, auth);
 }
 model.addAttribute("msg", "You've been logged out successfully.");
 return "login";
 }
 
 @RequestMapping(value = "/secure", method = RequestMethod.GET)
 public String securePage(ModelMap model) {
 model.addAttribute("user", getPrincipal());
 return "secure";
 }

 @RequestMapping(value = "/Access_Denied", method = RequestMethod.GET)
 public String accessDeniedPage(ModelMap model) {
 model.addAttribute("user", getPrincipal());
 return "accessDenied";
 }
 
 private String getPrincipal(){
 String userName = null;
 Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
 
 if (principal instanceof UserDetails) {
 userName = ((UserDetails)principal).getUsername();
 } else {
 userName = principal.toString();
 }
 return userName;
 }
 
 private boolean hasRole(String role) {
 Collection<GrantedAuthority> authorities = (Collection<GrantedAuthority>)SecurityContextHolder.getContext().getAuthentication().getAuthorities();
 boolean hasRole = false;
 for (GrantedAuthority authority : authorities) {
 hasRole = authority.getAuthority().equals(role);
 if (hasRole) {
 break;
 }
 }
 return hasRole;
 }
}
STEP 11 :- Create jsp files in /WebContent/WEB-INF/views folder
  • Filename: login.jsp
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@page session="true"%>
<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 Login Form (Database Authentication)</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='/login' />" method='POST'>

 <table>
 <tr>
 <td>User:</td>
 <td><input type='text' name='username'></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>
 </div>

</body>
</html>

  • Filename: welcome.jsp
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags"%>
<html>
<head>
 <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
 <title>Welcome page</title>
</head>
<body>
 Dear <strong>${user}</strong>, Welcome to Home Page.
 <a href="<c:url value="/logout" />">Logout</a>
 
 <br/>
 <br/>
 <div>
 <label>View all information| This part is visible to Everyone</label>
 </div>
 <br/>
 <br/>
 <div>
 Please click this to visit 
 <a href="<c:url value="/secure" />">Secure</a> Page.
 </div>
 <br/>
 <div>
 <sec:authorize access="hasRole('ADMIN')">
 <label><a href="#">Edit this page</a> | This part is visible only to ADMIN</label>
 </sec:authorize>
 </div>
 <br/>
 <div>
 <sec:authorize access="hasRole('API')">
 <label><a href="#">Start backup</a> | This part is visible only to one who has API rights.</label>
 </sec:authorize>
 </div>
 
 <br/>
 <div>
 <sec:authorize access="hasRole('ADMIN') and hasRole('API')">
 <label><a href="#">Start backup</a> | This part is visible only to one who is both ADMIN & API</label>
 </sec:authorize>
 </div>
</html>

  • Filename: secure.jsp
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags"%>
<html>
<head>
 <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
 <title>Welcome page</title>
</head>
<body>
 Dear <strong>${user}</strong>, Welcome to Secured Page.
 <a href="<c:url value="/logout" />">Logout</a>
 
 <br/>
 <br/>
 <div>
 <label>This is secured</label>
 </div>
 </body>
 </html>

  • Filename: accessDenied.jsp
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html>
<head>
 <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
 <title>AccessDenied page</title>
</head>
<body>
 Dear <strong>${user}</strong>, You are not authorized to access this page
 <a href="<c:url value="/logout" />">Logout</a>
</body>
</html>

STEP 12 :- Run your project enter below URL in your browser

http://localhost:8080/SpringSecurityFilterAnnotation/

Keep visiting TutorialsDesk for more tutorials and practical programming examples on Spring MVC. Hope we are able to explain you Spring MVC Security @PreFilter and @PostFilter annotation Example, if you have any questions or suggestions please write to us using contact us form.

Please share us on social media if you like the tutorial.