dineshonjava

Spring Security Annotation Based Hello World Example

In this tutorial of Spring Security Annotation Based Hello World Example, we will take a look into very simple hello world example of spring security annotation based in a Spring MVC environment. In previous tutorial We have seen same example in the Spring Security XML based in a Spring MVC. Here we going to show you how to create application in annotation or java config based spring security configuration.

Here I have used technologies as below :
  • Spring 4.3.5.RELEASE
  • Spring Security 4.2.1.RELEASE
  • STS 3.5.1
  • JDK 1.8
  • Maven 4
  • Tomcat 8 (Servlet 3.x)


In this tutorial I am using total java based configuration for web application as well so here I am using WebApplicationInitializer implementation to load the Spring Application Context file by Context Loader automatically. But this java configuration is required supported in Servlet 3.x container only i.e as of Tomcat 7 and as of Jetty 8.

Maven Dependency for this application
For this application we have following minimum maven dependencies. For Spring Security into web application we have required two jars only spring-security-web.jar and spring-security-context.jar.

<properties>
   <spring.version>4.3.5.RELEASE</spring.version>
   <spring.security.version>4.2.1.RELEASE</spring.security.version>
  </properties>
  
  <dependencies>
   <dependency>
     <groupId>org.springframework</groupId>
     <artifactId>spring-webmvc</artifactId>
     <version>${spring.version}</version>
 </dependency>
 
 <dependency>
     <groupId>org.springframework.security</groupId>
     <artifactId>spring-security-config</artifactId>
     <version>${spring.security.version}</version>
 </dependency>
 
 <dependency>
     <groupId>org.springframework.security</groupId>
     <artifactId>spring-security-web</artifactId>
     <version>${spring.security.version}</version>
 </dependency>
 
 <dependency>
     <groupId>jstl</groupId>
     <artifactId>jstl</artifactId>
     <version>1.2</version>
 </dependency>
  
  </dependencies>

Application Directory Structure
Here I have created web application using Maven as below directory structure for this application.

Spring Security Annotation Based Hello World Example

Spring Security Annotation or Java Configuration
Here we will see how to configure Spring Security in the Spring MVC application based annotation or java configuration. Follow my another tutorial of Spring Security Java based Annotation Configuration for more detail information about all Spring Security annotations and its used in the application.

Let's create a Spring Security configuration file and annotated it with @EnableWebSecurity as below:

SecurityConfig.java

/**
 * 
 */
package com.doj.app.config.security;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

/**
 * @author Dinesh.Rajput
 *
 */
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
 
 //Override Default configuration in WebSecurityConfigurerAdapter for custom login form and authorize requests
 //We specified multiple URL patterns that any user can access like "/login/".
 //Any URL that starts with "/admin/" will be restricted to users who have the role "ROLE_ADMIN". 
 //Any URL that has not already been matched on only requires that the user be authenticated
 @Override
 protected void configure(HttpSecurity http) throws Exception {
  http
   .authorizeRequests()                                                                
    .antMatchers("/resources/**", "/login").permitAll()                  
    .antMatchers("/admin/**").hasRole("ADMIN")                                      
    .antMatchers("/db/**").access("hasRole('ADMIN') and hasRole('DBA')")            
    .anyRequest().authenticated()                                                   
    .and()
   .formLogin();
 }
 //In memory authentication java configuration
 //Not web-specific
 @Autowired
 public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
  auth
   .inMemoryAuthentication() //Adds a UserDetailsManagerConfigurer
    //login, password and supported role
    .withUser("user").password("password").roles("USER").and()
    .withUser("admin").password("dinesh").roles("ADMIN");
 }
}


In the previous example, its equivalent XML configuration file for Spring Security.
applicationContext-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:security="http://www.springframework.org/schema/security"
       xmlns:p="http://www.springframework.org/schema/p" 
       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-3.1.xsd">

   <security:http auto-config="true">
  <security:intercept-url pattern="/admin/**" access="ROLE_USER" />
  <security:intercept-url pattern="/*" access="ROLE_USER" />
 </security:http>

    <security:authentication-manager>
   <security:authentication-provider>
     <security:user-service>
   <security:user name="user" password="password" authorities="ROLE_USER" />
   <security:user name="admin" password="dinesh" authorities="ROLE_ADMIN" />
     </security:user-service>
   </security:authentication-provider>
 </security:authentication-manager>

</beans>


Here I have overridden configure(HttpSecurity http) method of WebSecurityConfigurerAdapter class of Spring Security for customization in authorization and authentication mechanism. By default this configure(HttpSecurity http) method of WebSecurityConfigurerAdapter apply the authentication to all application calls or URLs. But here URL like "/resources/**", "/login" permit for all without authentication required by using permitAll() method and URL like "/admin/**" is required a special ADMIN role for accessing it and else URLs of the web application is required authentication only for any ROLE either ADMIN, USER, DB etc..

Note: Access control for more specific URLs like "/admin/**", "/db/**" should be always define first above to the general case like "/**".

Note: As of Spring Security 4.0, @EnableWebMvcSecurity is deprecated. The replacement is @EnableWebSecurity which will determine adding the Spring MVC features based upon the classpath. To enable Spring Security integration with Spring MVC add the @EnableWebSecurity annotation to your configuration.

Loading Spring Security Filters Chain to Container
Spring Security has lot of filters to apply the security to the web application. But but we don't need to configure all filters in to web.xml or ApplicationInitializer class file of the application. Spring Security provides us a Special Filter bean class "SpringSecurityFilterChain" it is responsible for registering all filters into spring application context file as beans. And one more filter of Spring Security, "DelegatingFilterProxy" delegates the request to associated registered bean class into application context file with same name as filter name in the web.xml file.

Let's see the below file that is responsible to loading Spring Security Context file to container.

SecurityWebApplicationInitializer.java

/**
 * 
 */
package com.doj.app.web;

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

/**
 * @author Dinesh.Rajput
 *
 */
public class SecurityWebApplicationInitializer extends
  AbstractSecurityWebApplicationInitializer {

}


This class SecurityWebApplicationInitializer.java does not have any body here but it extends AbstractSecurityWebApplicationInitializer, it will load the springSecurityFilterChain automatically define internally by Spring Security Framework. In previous XML based example it's equivalent XML configuration in the web.xml file as below:

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

That is all about the Spring Security Annotation Based basic java configuration for this example. Let's see below file has Spring MVC configuration for this application.

WebMvcConfig.java
/**
 * 
 */
package com.doj.app.config.web;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.view.InternalResourceViewResolver;

/**
 * @author Dinesh.Rajput
 *
 */
@Configuration
@EnableWebMvc
@ComponentScan("com.doj.app.web.controller")
public class WebMvcConfig {
 
 @Bean
 public ViewResolver viewResolver(){
  InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
  viewResolver.setPrefix("/WEB-INF/view/");
  viewResolver.setSuffix(".jsp");
  return viewResolver;
 }
}

It's equivalent configuration in the XML based configuration:

<context:component-scan base-package="com.doj.app.web.controller" />

<bean id="jspViewResolver"
 class="org.springframework.web.servlet.view.InternalResourceViewResolver">
 <property name="viewClass"
  value="org.springframework.web.servlet.view.JstlView" />
 <property name="prefix" value="/WEB-INF/view/" />
 <property name="suffix" value=".jsp" />
</bean>

Let's see WebApplicationInitializer class to load every thing to web container. This is file is equivalent to web.xml file in the XML based application.

ApplicationInitializer.java

/**
 * 
 */
package com.doj.app.web;

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

import com.doj.app.config.RootConfig;
import com.doj.app.config.security.SecurityConfig;
import com.doj.app.config.web.WebMvcConfig;

/**
 * @author Dinesh.Rajput
 *
 */
public class ApplicationInitializer extends
  AbstractAnnotationConfigDispatcherServletInitializer {

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

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

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

}


Finally we have a HomeController of application to handling requests from browser.

package com.doj.app.web.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.GetMapping;

/**
 * @author Dinesh Rajput
 *
 */
@Controller
public class HomeController {
 
 @GetMapping("/")
 public String home(ModelMap model) {
  model.addAttribute("message", "Learn Spring Security Hello World Example with Annotations");
  model.addAttribute("author", "User of Dinesh on Java");
  return "home";
 }
 
 @GetMapping("/admin/")
 public String admin(ModelMap model) {
  model.addAttribute("message", "Create Spring Security Hello World Example with Annotations");
  model.addAttribute("author", "Admin of Dinesh on Java");
  return "admin";
 }
}


Download Source Code of this Spring Security Annotation Example from Git.

Demo

Let's see demo of this example after successfully deployed to the tomcat 7 or 8.
After running server try to access the application then Spring Security will intercept the request and redirect to /login, and a default login form is displayed.

spring-security-demo-login-page

If username and password is incorrect or empty submit then it will display error messages, and Spring Security's ExceptionTranslationFilter will redirect to this URL /login?error.

spring-security-demo-login-page-with-error-messages

If username and password is correct then it will redirect the request to the original requested URL and display the page.

spring-security-demo-home-page

Suppose we have logged in with "user" and "password" as configured above in the Spring Security Configuration, This user has Role "USER" and we are trying to access unauthorized resource of admin, required "ADMIN" role, Spring will display the 403 access denied page.

spring-security-demo-403-page