In this tutorial I will show you the most useful annotation is @PreAuthorize which decides whether a method can actually be invoked or not based on user’s role. hasRole() method returns true if the current principal has the specified role. By default if the supplied role does not start with ROLE_ will be added. This can be customized by modifying the defaultRolePrefix on DefaultWebSecurityExpressionHandler.

You can check my tutorial on hasPermission @PreAuthorize annotation – hasPermission example in Spring Security

This @PreAuthorize annotation will be applied on the method as a Method Security Expression. For example,

@PreAuthorize("hasRole('USER')")
public void create(Contact contact);

which means that access will only be allowed for users with the role ROLE_USER. Obviously the same thing could easily be achieved using a traditional configuration and a simple configuration attribute for the required role.

Let’s see the working example below

Below is the project’s pom file

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>jeejava</groupId>
	<artifactId>spring-auth-annotations</artifactId>
	<packaging>war</packaging>
	<version>0.0.1-SNAPSHOT</version>
	<name>spring-auth-annotations Maven Webapp</name>
	<url>http://maven.apache.org</url>

	<properties>
		<java.version>1.8</java.version>
		<jackson.version>2.5.3</jackson.version>
		<spring.version>4.3.8.RELEASE</spring.version>
		<spring.security.version>4.2.2.RELEASE</spring.security.version>
	</properties>

	<dependencies>
		<!-- Spring mvc -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
			<version>${spring.version}</version>
		</dependency>

		<!-- Spring Security -->
		<dependency>
			<groupId>org.springframework.security</groupId>
			<artifactId>spring-security-web</artifactId>
			<version>${spring.security.version}</version>
		</dependency>

		<dependency>
			<groupId>org.springframework.security</groupId>
			<artifactId>spring-security-config</artifactId>
			<version>${spring.security.version}</version>
		</dependency>

		<!-- Servlet -->
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>javax.servlet-api</artifactId>
			<version>3.1.0</version>
			<scope>provided</scope>
		</dependency>

		<dependency>
			<groupId>javax.servlet.jsp</groupId>
			<artifactId>javax.servlet.jsp-api</artifactId>
			<version>2.3.1</version>
			<scope>provided</scope>
		</dependency>

		<!-- jstl -->
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>jstl</artifactId>
			<version>1.2</version>
		</dependency>

		<!-- jackson -->
		<dependency>
			<groupId>com.fasterxml.jackson.core</groupId>
			<artifactId>jackson-databind</artifactId>
			<version>${jackson.version}</version>
		</dependency>
	</dependencies>

	<build>
		<finalName>spring-auth-annotations</finalName>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>2.3.2</version>
				<configuration>
					<source>${java.version}</source>
					<target>${java.version}</target>
				</configuration>
			</plugin>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-war-plugin</artifactId>
				<version>2.2</version>
				<configuration>
					<failOnMissingWebXml>false</failOnMissingWebXml>
				</configuration>
			</plugin>
		</plugins>
	</build>

</project>

Create the below required class. For more information please read http://docs.spring.io/spring-security/site/docs/3.2.3.RELEASE/apidocs/org/springframework/security/web/context/AbstractSecurityWebApplicationInitializer.html

package jeejava.security.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = { "jeejava.controller" })
public class WebMvcConfig {

}

Enable Web Security using below class. Configure global-method-security pre-post-annotations using Java configuration. Here, the in-memory authentication has been provided. In real life application, the authentication should happen through database or LDAP or any other third party API etc. Here, the static resources like css, js etc. files under static folder are excluded from spring security authentication.

package jeejava.security.config;

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

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

	@Override
	public void configure(WebSecurity web) throws Exception {
		web.ignoring().antMatchers("/static/**");
	}

	@Autowired
	public void registerGlobal(AuthenticationManagerBuilder auth) throws Exception {
		// in reality DB auth is required
		auth.inMemoryAuthentication().withUser("user").password("user").roles("USER").and().withUser("admin")
				.password("admin").roles("USER", "ADMIN");
	}

}

Here in the above class, admin has USER as well as ADMIN roles but user has only one role USER. Therefore admin can access its own URL as well as user’s URL but user can access only its own URL but not admin’s URL.

Below class is required in order to load the Dispatcher Servlet with mapping / and other configurations.

package jeejava.security.config;

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

public class MvcWebApplicationInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

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

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

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

}

Now create below REST Controller class to test the user’s access to a particular URL based on role using @PreAuthorize annotation.

package jeejava.controller;

import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {

	@PreAuthorize("hasRole('USER')")
	@RequestMapping("/user")
	public String userRole() {
		return "You have USER role";
	}

	@PreAuthorize("hasRole('ADMIN')")
	@RequestMapping("/admin")
	public String adminRole() {
		return "You have ADMIN role";
	}

}

Now when you deploy the application on Tomcat server and access the URL – http://localhost:8085/spring-auth-annotations/admin using credentials user/user then you will get HTTP Status 403 – Access is denied because user does not have role ADMIN but if you had logged in using credentials admin/admin, you could have got the access.

Thanks for reading.

Tags:

I am a professional Web developer, Enterprise Application developer, Software Engineer and Blogger. Connect me on Roy Tutorials | TwitterFacebook Google PlusLinkedin | Reddit

Leave a Reply

Your email address will not be published. Required fields are marked *