Spring Security Example Tutorial – How to limit number of User Session in Java

Spring security can limit number of session a user can have. If you are developing web application specially secure web application in Java J2EE then you must have come up with requirement similar to online banking portals have e.g. only one session per user at a time or no concurrent session per user. You can also implement this functionality without using spring security but with Spring security its just piece of cake with coffee :). Spring Security provides lots of Out of Box functionality a secure enterprise or web application needed like authentication, authorization, session management, password encoding, secure access, session timeout etc. In our spring security example we have seen how to do LDAP Authentication in Active directory using spring security and in this spring security example we will see how to limit number of session user can have in Java web application or restricting concurrent user session.

Spring Security Example: Limit Number of User Session

As I said it’s simple and easy when you use spring security framework or library. In fact is all declarative and no code is require to enable concurrent session disable functionality. You will need to include following xml snippet in your Spring Security Configuration file mostly named as applicaContext-security.xml. Here is sample spring security Example of limiting user session in Java web application:

<session-management invalid-session-url="/logout.html">
    <concurrency-control max-sessions="1" error-if-maximum-exceeded="true" />
</session-management>

As you see you can specify how many concurrent session per user is allowed, most secure system like online banking portals allow just one authenticate session per user. You can even specify a URL where user will be taken if they submit an invalid session identifier can be used to detect session timeout. Session-management element is used to capture session related stuff. Max-session specify how many concurrent authenticated session is allowed and if error-if-maximum-exceeded set to true it will flag error if user tries to login into another session.

Dependency

This code has dependency on spring-security framework. You need to download spring security jar like spring-security-web-3.1.0.jar and add into application classpath.

This simple example of spring security shows power of spring security, a small piece of xml snippet can add very useful and handy security feature in your Java web application. I recommend using spring security for your new or existing Java web application created using Servlet JSP.

That’s all on how to limit number of user session using spring security in Java web application. Let me know if you face any issue while implementing this security feature in your project.

 

An Intro to the Spring DispatcherServlet!

1. Introduction

Simply put, in the Front Controller design pattern, a single controller is responsible for directing incomingHttpRequests to all of an application’s other controllers and handlers.

Spring’s DispatcherServlet implements this pattern and is, therefore, responsible for correctly coordinating the HttpRequests to their right handlers.

In this article, we will examine the Spring DispatcherServlet’s request processing workflow and how to implement several of the interfaces that participate in this workflow.

2. DispatcherServlet Request Processing

Essentially, a DispatcherServlet handles an incoming HttpRequest, delegates the request, and processes that request according to the configured HandlerAdapter interfaces that have been implemented within the Spring application along with accompanying annotations specifying handlers, controller endpoints, and response objects.

Let’s get more in depth about how a DispatcherServlet processes a component:

  • the WebApplicationContext associated to a DispatcherServlet under the key DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE is searched for and made available to all of the elements of the process
  • The DispatcherServlet finds all implementations of the HandlerAdapter interface configured for your dispatcher using getHandler() – each found and configured implementation handles the request via handle()  through the remainder of the process
  • the LocaleResolver is optionally bound to the request to enable elements in the process to resolve the locale
  • the ThemeResolver is optionally bound to the request to let elements, such as views, determine which theme to use
  • if a MultipartResolver is specified, the request is inspected for MultipartFiles – any found are wrapped in a MultipartHttpServletRequest for further processing
  • HandlerExceptionResolver implementations declared in the WebApplicationContext pick up exceptions that are thrown during processing of the request

You can learn more about all the ways to register and set up a DispatcherServlet here.

3. HandlerAdapter Interfaces

The HandlerAdapter interface facilitates the use of controllers, servlets, HttpRequests, and HTTP paths through several specific interfaces. The HandlerAdapter interface thus plays an essential role through the many stages of the DispatcherServlet request processing workflow.

First, each HandlerAdapter implementation is placed into the HandlerExecutionChain from your dispatcher’s getHandler() method. Then, each of those implementations handle() the HttpServletRequest object as the execution chain proceeds.

In the following sections, we will explore a few of the most important and commonly used HandlerAdapters in greater detail.

3.1. Mappings

To understand mappings, we need to first look at how to annotate controllers since controllers are so essential to the HandlerMapping interface.

The SimpleControllerHandlerAdapter allows for the implementation of a controller explicitly without a @Controller annotation.

The RequestMappingHandlerAdapter supports methods annotated with the @RequestMapping annotation.

We’ll focus on the @Controller annotation here, but a helpful resource with several examples using the SimpleControllerHandlerAdapter is also available.

The @RequestMapping annotation sets the specific endpoint at which a handler will be available within the WebApplicationContext associated with it.

Let’s see an example of a Controller that exposes and handles the ‘/user/example’ endpoint:

1
2
3
4
5
6
7
8
9
10
@Controller
@RequestMapping("/user")
@ResponseBody
public class UserController {
 
    @GetMapping("/example")
    public User fetchUserExample() {
        // ...
    }
}

The paths specified by the @RequestMapping annotation are managed internally via the HandlerMapping interface.

The URLs structure is naturally relative to the DispatcherServlet itself – and determined by the servlet mapping.

Thus, if the DispatcherServlet is mapped to ‘/’, then all mappings are going to be covered by that mapping.

If, however, the servlet mapping is ‘/dispatcher‘ instead, then any @RequestMapping annotations are going to be relative to that root URL.

Remember that ‘/’ is not the same as ‘/*’ for servlet mappings! ‘/’ is the default mapping and exposes all URL’s to the dispatcher’s area of responsibility.

‘/*’  is confusing to a lot of newer Spring developers. It does not specify that all paths with the same URL context are under the dispatcher’s area of responsibility. Instead, it overrides and ignores the other dispatcher mappings. So, ‘/example’ will come up as a 404!

For that reason, ‘/*’ shouldn’t be used except in very limited circumstances (like configuring a filter).

3.2. HTTP Request Handling

The core responsibility of a DispatcherServlet is to dispatch incoming HttpRequests to the correct handlersspecified with the @Controller or @RestController annotations.

As a sidenote, the main difference between @Controller and @RestController is how the response is generated – the @RestController also defines @ResponseBody by default.

A writeup where we go into much greater depth regarding Spring’s controllers can be found here.

3.3. The ViewResolver Interface

A ViewResolver is attached to a DispatcherServlet as a configuration setting on an ApplicationContext object.

A ViewResolver determines both what kind of views are served by the dispatcher and from where they are served.

Here’s an example configuration which we’ll place into our WebMvcConfigurerAdapter for rendering JSP pages:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Configuration
@EnableWebMvc
@ComponentScan("com.baeldung.springdispatcherservlet")
public class AppConfig extends WebMvcConfigurerAdapter {
    @Bean
    public UrlBasedViewResolver viewResolver() {
        UrlBasedViewResolver resolver
          = new UrlBasedViewResolver();
        resolver.setPrefix("/WEB-INF/jsp/");
        resolver.setSuffix(".jsp");
        resolver.setViewClass(JstlView.class);
        return resolver;
    }
}

Very straight-forward! There are three main parts to this:

  1. setting the prefix, which sets the default URL path to find the set views within
  2. the default view type which is set via the suffix
  3. setting a view class on the resolver which allows technologies like JSTL or Tiles to be associated with the rendered views

One common question involves how precisely a dispatcher’s ViewResolver and the overall project directory structure are related. Let’s take a look at the basics.

Here’s an example path configuration for an InternalViewResolver using Spring’s XML configuration:

1
<property name="prefix" value="/jsp/"/>

For the sake of our example, we’ll assume that our application is being hosted on:

This is the default address and port for a locally hosted Apache Tomcat server.

Assuming that our application is called dispatcherexample-1.0.0, our JSP views will be accessible from:

The path for these views within an ordinary Spring project with Maven is this:

1
2
3
4
5
6
7
src -|
     main -|
            java
            resources
            webapp -|
                    jsp
                    WEB-INF

The default location for views is within WEB-INF. The path specified for our InternalViewResolver in the snippet above determines the subdirectory of ‘src/main/webapp’ in which your views will be available.

 3.4. The LocaleResolver Interface

The primary way to customize session, request, or cookie information for our dispatcher is through theLocaleResolver interface.

CookieLocaleResolver is an implementation allowing the configuration of stateless application properties using cookies. Let’s add it to AppConfig.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Bean
public CookieLocaleResolver cookieLocaleResolverExample() {
    CookieLocaleResolver localeResolver
      = new CookieLocaleResolver();
    localeResolver.setDefaultLocale(Locale.ENGLISH);
    localeResolver.setCookieName("locale-cookie-resolver-example");
    localeResolver.setCookieMaxAge(3600);
    return localeResolver;
}
@Bean
public LocaleResolver sessionLocaleResolver() {
    SessionLocaleResolver localeResolver = new SessionLocaleResolver();
    localeResolver.setDefaultLocale(Locale.US);
    localResolver.setDefaultTimeZone(TimeZone.getTimeZone("UTC"));
    return localeResolver;
}

SessionLocaleResolver allows for session-specific configuration in a stateful application.

The setDefaultLocale() method represents a geographical, political, or cultural region, whereas setDefaultTimeZone() determines the relevant TimeZone object for the application Bean in question.

Both methods are available on each of the above implementations of LocaleResolver.

3.5. The ThemeResolver Interface

Spring provides stylistic theming for our views.

Let’s take a look at how to configure our dispatcher to handle themes.

First, let’s set up all the configuration necessary to find and use our static theme files. We need to set a static resource location for our ThemeSource to configure the actual Themes themselves (Theme objects contain all of the configuration information stipulated in those files). Add this to AppConfig:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
    registry.addResourceHandler("/resources/**")
      .addResourceLocations("/", "/resources/")
      .setCachePeriod(3600)
      .resourceChain(true)
      .addResolver(new PathResourceResolver());
}
@Bean
public ResourceBundleThemeSource themeSource() {
    ResourceBundleThemeSource themeSource
      = new ResourceBundleThemeSource();
    themeSource.setDefaultEncoding("UTF-8");
    themeSource.setBasenamePrefix("themes.");
    return themeSource;
}

Requests managed by the DispatcherServlet can modify the theme through a specified parameter passed into setParamName() available on the ThemeChangeInterceptor object. Add to AppConfig:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Bean
public CookieThemeResolver themeResolver() {
    CookieThemeResolver resolver = new CookieThemeResolver();
    resolver.setDefaultThemeName("example");
    resolver.setCookieName("example-theme-cookie");
    return resolver;
}
@Bean
public ThemeChangeInterceptor themeChangeInterceptor() {
   ThemeChangeInterceptor interceptor
     = new ThemeChangeInterceptor();
   interceptor.setParamName("theme");
   return interceptor;
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(themeChangeInterceptor());
}

The following JSP tag is added to our view to make the correct styling appear:

1
<link rel="stylesheet" href="${ctx}/<spring:theme code='styleSheet'/>" type="text/css"/>

The following URL request renders the example theme using the ‘theme’ parameter passed into our configured ThemeChangeIntercepter:

3.6. The MultipartResolver Interface

A MultipartResolver implementation inspects a request for multiparts and wraps them in a MultipartHttpServletRequest for further processing by other elements in the process if at least one multipart is found. Add to AppConfig:

1
2
3
4
5
6
7
8
@Bean
public CommonsMultipartResolver multipartResolver()
  throws IOException {
    CommonsMultipartResolver resolver
      = new CommonsMultipartResolver();
    resolver.setMaxUploadSize(10000000);
    return resolver;
}

Now that we’ve configured our MultipartResolver bean, let’s set up a controller to process MultipartFile requests:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
@Controller
public class MultipartController {
    @Autowired
    ServletContext context;
    @PostMapping("/upload")
    public ModelAndView FileuploadController(
      @RequestParam("file") MultipartFile file)
      throws IOException {
        ModelAndView modelAndView = new ModelAndView("index");
        InputStream in = file.getInputStream();
        String path = new File(".").getAbsolutePath();
        FileOutputStream f = new FileOutputStream(
          path.substring(0, path.length()-1)
          + "/uploads/" + file.getOriginalFilename());
        int ch;
        while ((ch = in.read()) != -1) {
            f.write(ch);
        }
        f.flush();
        f.close();
        modelAndView.getModel()
          .put("message", "File uploaded successfully!");
        return modelAndView;
    }
}

We can use a normal form to submit a file to the specified endpoint. Uploaded files will be available in ‘CATALINA_HOME/bin/uploads’.

3.7. The HandlerExceptionResolver Interface

Spring’s HandlerExceptionResolver provides uniform error handling for an entire web application, a single controller, or a set of controllers.

To provide application-wide custom exception handling, create a class annotated with @ControllerAdvice:

1
2
3
4
5
6
7
8
9
@ControllerAdvice
public class ExampleGlobalExceptionHandler {
    @ExceptionHandler
    @ResponseBody
    public String handleExampleException(Exception e) {
        // ...
    }
}

Any methods within that class annotated with @ExceptionHandler will be available on every controller within dispatcher’s area of responsibility.

Implementations of the HandlerExceptionResolver interface in the DispatcherServlet’s ApplicationContext are available to intercept a specific controller under that dispatcher’s area of responsibility whenever @ExceptionHandler is used as an annotation, and the correct class is passed in as a parameter:

1
2
3
4
5
6
7
8
9
@Controller
public class FooController{
    @ExceptionHandler({ CustomException1.class, CustomException2.class })
    public void handleException() {
        // ...
    }
    // ...
}

The handleException() method will now serve as an exception handler for FooController in our example above if either exception CustomException1 or CustomException2 occurs.

Here’s an article that goes more in depth about exception handling in a Spring web application.

 4. Conclusion

In this tutorial, we’ve reviewed Spring’s DispatcherServlet and several ways to configure it.

As always, the source code used in this tutorial is available over on Github.

Spring MVC Execution Flow

f2SzS

Spring MVC 3.2 Execution Flow

Step 1: First request will be received by DispatcherServlet
Step 2: DispatcherServlet will take the help of HandlerMapping and get to know the Controller class name associated with the given request
Step 3: So request transfer to the Controller, and then controller will process the request by executing appropriate methods and returns ModeAndView object (contains Model data and View name) back to the DispatcherServlet
Step 4: Now DispatcherServlet send the model object to the ViewResolver to get the actual view page
Step 5: Finally DispatcherServlet will pass the Model object to the View page to display the result

That’s it :-)