Introduction

In this tutorial I will show you an example on @PreAuthorize annotation – hasRole example in Spring Security. @PreAuthorize is the most useful annotation that 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

Where is @PreAuthorize applicable?

This @PreAuthorize annotation is generally applicable 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.

Prerequisites

Eclipse, Java 1.8, Gradle 4.10.2, Spring Boot 2.1.5

Example with Source Code

Let’s see the working example below…

Creating Project

Create a gradle project in Eclipse, the project structure looks similar to the below image:

@PreAuthorize annotation - hasRole example in Spring Security

Updating Build Script

We will add the required dependencies for our Spring Security PreAuthorize hasRole example.

We have added dependencies for spring security.

buildscript {
	ext {
		springBootVersion = '2.1.5.RELEASE'
	}
    repositories {
    	mavenLocal()
    	mavenCentral()
    }
    dependencies {
    	classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
    }
}
apply plugin: 'java'
apply plugin: 'org.springframework.boot'
sourceCompatibility = 1.8
targetCompatibility = 1.8
repositories {
	mavenLocal()
    mavenCentral()
}
dependencies {
	compile("org.springframework.boot:spring-boot-starter-web:${springBootVersion}")
	compile("org.springframework.boot:spring-boot-starter-security:${springBootVersion}")
}

Creating Configuration Class

The below class configures Spring Security.

We need below security configuration using Java annotation in order to use authorization.

Enable Web Security using below class. Configure global-method-security pre-post-annotation using Java configuration.

Here, the in-memory authentication has been provided. Ideally in the application, the authentication should happen through database or LDAP or any other third party API etc.

We have used PasswordEncoder because plain text password is not acceptable in current version of Spring Security and you will get below exception if you do not use PasswordEncoder.

java.lang.IllegalArgumentException: There is no PasswordEncoder mapped for the id "null"
	at org.springframework.security.crypto.password.DelegatingPasswordEncoder$UnmappedIdPasswordEncoder.matches(DelegatingPasswordEncoder.java:244) ~[spring-security-core-5.1.5.RELEASE.jar:5.1.5.RELEASE]

As the passwords are in encrypted format in the below class, so you won’t find it easier until I tell you. The password for user is user and for admin is admin.

Source code of the configuration class is given below:

package com.roytuts.spring.security.preauth.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
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.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SpringPreAuthorizeSecurityConfig extends WebSecurityConfigurerAdapter {
	@Autowired
	public void registerGlobal(AuthenticationManagerBuilder auth) throws Exception {
		// Ideally database authentication is required
		auth.inMemoryAuthentication().passwordEncoder(passwordEncoder()).withUser("user")
				.password("$2a$10$9Xn39aPf4LhDpRGNWvDFqu.T5ZPHbyh8iNQDSb4aNSnLqE2u2efIu").roles("USER").and()
				.passwordEncoder(passwordEncoder()).withUser("admin")
				.password("$2a$10$dl8TemMlPH7Z/mpBurCX8O4lu0FoWbXnhsHTYXVsmgXyzagn..8rK").roles("USER", "ADMIN");
	}
	@Bean
	public PasswordEncoder passwordEncoder() {
		return new BCryptPasswordEncoder();
	}
}

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.

Creating REST Controller

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

package com.roytuts.spring.security.preauth.rest.controller;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class PreAuthorizeRestController {
	@GetMapping("/user")
	@PreAuthorize("hasRole('USER')")
	public ResponseEntity<String> defaultPage(Model model) {
		return new ResponseEntity<String>("You have USER role.", HttpStatus.OK);
	}
	@GetMapping("/admin")
	@PreAuthorize("hasRole('ADMIN')")
	public ResponseEntity<String> getAllBlogs(Model model) {
		return new ResponseEntity<String>("You have ADMIN role.", HttpStatus.OK);
	}
}

Creating Main Class

Spring Boot application created as standalone application and can be easily deployed into embedded Tomcat server using main class.

package com.roytuts.spring.security.preauth;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication(scanBasePackages = "com.roytuts.spring.security.preauth")
public class SpringPreAuthorize {
	public static void main(String[] args) {
		SpringApplication.run(SpringPreAuthorize.class, args);
	}
}

Testing the Application

Run the main class to deploy your application into Tomcat server.

Now access the URL http://localhost:8080/admin using credentials user/user then you will get HTTP Status 403 – Access is denied because user does not have role ADMIN.

preauthorize hasRole

But if you had logged in using credentials admin/admin, you could have got the access.

spring security hasrole

Source Code

You can download source code.

Thanks for reading.

Tags:

Leave a Reply

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