Sunday, January 14, 2024

Difference between @PreAuthorized and @RolesAllowed Annotations in Java (with Example)

Hello guys, In Java programming and backend application development security plays a pivotal role in safeguarding applications from unauthorized access and malicious activities. To ensure proper control over access rights, Java developers often utilize annotations, such as @PreAuthorized and @RolesAllowed of Spring Security framework. Earlier, I have shared how to setup Spring Security and talked about HTTP Basic Authentication and In this article, we will explore the functionality of both annotations, their differences, and use real-world and programming examples to illustrate their significance.


1. @PreAuthorized Annotation

The @PreAuthorized annotation is part of the Spring Security framework, which is widely used to implement security features in Java applications. This annotation allows developers to specify access control rules at the method level, indicating that the method can only be executed if certain pre-authorization conditions are met.

The primary purpose of @PreAuthorized is to ensure that the user attempting to access the method has the required permissions or privileges to perform the operation. These permissions are typically defined in a security configuration file, and the Spring Security framework validates them during runtime.


Real-World Example:

Let's consider a hypothetical web application with different user roles: "ADMIN," "MODERATOR," and "USER." The application has a method called "deleteUserAccount" that can only be accessed by users with the "ADMIN" role. To enforce this, we can use the @PreAuthorized annotation as follows:


@PreAuthorized("hasRole('ADMIN')")

public void deleteUserAccount(String userId) {

    // Code to delete the user account

}


In this example, the deleteUserAccount() method is annotated with @PreAuthorized, and the expression "hasRole('ADMIN')" specifies that only users with the "ADMIN" role can invoke this method. If a user without the required role attempts to call this method, the Spring Security framework will throw an AccessDeniedException, preventing unauthorized access.


Difference @PreAuthorized and @RolesAllowed Annotations in Java



2. @RolesAllowed Annotation

Similar to @PreAuthorized, @RolesAllowed allows developers to define access control constraints on methods, but it follows a different approach.

@RolesAllowed focuses on defining roles or groups that are allowed to access a particular method. The roles are typically mapped to security defined by the underlying application server or container. Unlike @PreAuthorized, which relies on Spring Security, @RolesAllowed is part of the core Java EE specifications.


Real-World Example:

Suppose we have a RESTful web service for a banking application that provides access to account information. The service has a method called "getAccountBalance," which can only be accessed by users with the "CUSTOMER" role. We can use the @RolesAllowed annotation as shown below:

@RolesAllowed("CUSTOMER")

public BigDecimal getAccountBalance(String accountId) {

    // Code to retrieve account balance

}


In this example, the getAccountBalance() method is annotated with @RolesAllowed, and it explicitly specifies that only users with the "CUSTOMER" role can access it. If a user without the required role attempts to invoke this method, the Java EE container will handle the authorization process and prevent unauthorized access.


Differences between @PreAuthorized and @RolesAllowed

While both annotations serve the purpose of enforcing access control, they have distinct differences:


1. Framework Dependency

- @PreAuthorized is specific to the Spring Security framework, which means it requires the application to be built using Spring Security for the annotation to work correctly.

- On the other hand, @RolesAllowed is part of the Java EE specifications, making it accessible in any Java EE-compliant container or application server without any additional dependencies.


2. Expression Language

- @PreAuthorized uses SpEL (Spring Expression Language) to define complex authorization rules. SpEL allows developers to use powerful expressions to check for roles, permissions, and other contextual information during authorization.

- @RolesAllowed, being a part of Java EE, relies on simple role names to define access control. It does not provide the flexibility of SpEL and can only check for the presence of specific roles without evaluating complex expressions.


3. Method Signature

- @PreAuthorized can be applied at the method level and supports finer-grained control over authorization by evaluating complex expressions and conditions.

- @RolesAllowed can also be used at the method level, but it focuses solely on specifying allowed roles for accessing the method, making it more suitable for straightforward role-based authorization.


Let’s demonstrate the functionality of the `@PreAuthorize` and `@RolesAllowed` annotations in a Java Spring Boot application, we'll create a simple RESTful API for managing user accounts. The API will have two endpoints, one requiring the "ADMIN" role and the other requiring the "USER" role. We'll use Spring Security to handle the authorization process and secure the endpoints with the respective annotations.

Make sure you have Spring Boot and Spring Security dependencies set up in your project. If you are using Maven, include the following dependencies in your `pom.xml` file:


pom.xml

<!-- Spring Boot Starter -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>



<!-- Spring Security -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

Now, let's create the Java classes for the demonstration:


UserAccountController.java

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



@RestController

@RequestMapping("/api")

public class UserAccountController {



    @GetMapping("/admin")

    @PreAuthorize("hasRole('ADMIN')")

    public String adminEndpoint() {

        return "Welcome, Admin!";

    }



    @GetMapping("/user")

    @Secured("ROLE_USER")

    public String userEndpoint() {

        return "Hello, User!";

    }

}


In this class, we've created two endpoints - `/admin` and `/user`. The `/admin` endpoint is protected by `@PreAuthorize` annotation, requiring the "ADMIN" role, and the `/user` endpoint is protected by `@Secured` annotation, requiring the "USER" role.


SecurityConfig.java

import org.springframework.context.annotation.Configuration;

import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;

import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;



@Configuration

@EnableWebSecurity

public class SecurityConfig extends WebSecurityConfigurerAdapter {



    @Override

    protected void configure(HttpSecurity http) throws Exception {

        http.authorizeRequests()

                .antMatchers("/api/admin").hasRole("ADMIN")

                .antMatchers("/api/user").hasRole("USER")

                .anyRequest().authenticated()

                .and()

                .httpBasic();

    }

}


In this class, we've created a `SecurityConfig` class that extends `WebSecurityConfigurerAdapter`, which allows us to customize Spring Security's configuration. We've used `http.authorizeRequests()` to define the access rules for different endpoints. The `.antMatchers()` method is used to specify the endpoints, and we've used `.hasRole()` to require specific roles.


DemoApplication.java

import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;



@SpringBootApplication

public class DemoApplication {



    public static void main(String[] args) {

        SpringApplication.run(DemoApplication.class, args);

    }

}

application.properties

spring.security.user.name=admin

spring.security.user.password=admin123


In this example, we've set up a default user with the username "admin" and password "admin123" for testing purposes.


Now, when you run the application, it will start up and you can test the endpoints using any HTTP client or browser:

- To access the `/admin` endpoint, you'll need to provide the credentials of the default user (username: "admin", password: "admin123"). 

If the credentials are correct and the user has the "ADMIN" role, you will get the response "Welcome, Admin!"

- To access the `/user` endpoint, you don't need any additional credentials. However, the user must have the "USER" role to get the response "Hello, User!"


If you try to access any other endpoints not specified in the `SecurityConfig` class, Spring Security will prompt you to provide valid credentials. This demonstrates how the @PreAuthorize and @RolesAllowed annotations effectively secure the endpoints based on their respective roles.


Conclusion

That's all about difference between @PreAuthorized and @RolesAllowed Annotation in Java. In conclusion, both @PreAuthorized and @RolesAllowed annotations are valuable tools for implementing access control in Java applications. While @PreAuthorized is closely associated with the Spring Security framework and provides the flexibility of SpEL for defining complex authorization rules, @RolesAllowed is part of the Java EE specifications and offers a straightforward approach to role-based authorization.

The choice between the two annotations largely depends on the application's architectural design and the frameworks being used. Developers working with Spring Security might prefer @PreAuthorized for its expressive power, whereas those working within Java EE environments can conveniently use @RolesAllowed without additional dependencies.

By understanding the functionality and differences between @PreAuthorized and @RolesAllowed, Java developers can make informed decisions on how to secure their applications effectively while ensuring proper access control mechanisms are in place.

I hope this little effort has helped you grasp the topic. 


Other Spring Tutorials and interview Questions you may like to explore

  • Difference between @RestControler and @Controller in Spring MVC? (answer)
  • 23 Spring MVC Interview questions for 2 to 3 years experienced (list)
  • Top 5 Courses to Learn Microservices with Spring and Java (courses)
  • What is the use of DispatcherServlet in Spring MVC? (answer)
  • Spring Security Official Documentation (docs)
  • 15 Spring Boot Interview Questions for Java Programmers (questions)
  • Does Spring certification help in Job and Career? (article)
  • 10 Best Spring Security and OAuth2 Courses  (best courses)
  • My favorite courses to learn Software Architecture (courses)
  • Top 5 Spring Certification Mock Exams (list)
  • 10 Advanced Spring Boot Courses for Experienced Java developers (courses)
  • 5 Courses to Learn Spring Framework in-depth (courses)
  • Difference between @Autowired and @Injection annotations in Spring? (answer)
  • 10 Spring MVC Annotations Every Java developer should know (annotations)
  • 5 Courses to Learn Spring Boot for Beginners (courses)
  • 5 Spring and Hibernate online courses for Java developers (list)
  • 10 Free Spring Boot Courses for Beginners (free courses)

No comments:

Post a Comment

Feel free to comment, ask questions if you have any doubt.