Wednesday, July 10, 2024

Difference between @Secured vs @RolesAllowed vs @PreAuthorize, @PostAuthorize Annotations in Spring Security

Spring Security is a powerful framework to implement security on Spring based Java web application as well as on security RESTful Web Services. It also provides method level security, which means restricting access to a method depending upon role and permissions of object. If a user calling the method has access the method will be executed, otherwise AccessDeniedException will be thrown by Spring Security. All these annotations e.g. @Secured, @RolesAllowed, @PreAuthorize, and @PostAuthorize is used to implement method level security in Spring security, but there are some subtle difference between them. 

For example, both @Secured and @RolesAllowed does the same thing i.e. allows access to the method with specified roles but @RolesAllowed is a standard Java annotation, defined in JSR 250, while @Secured is an old Spring Security annotation. 

It's a general best practices to prefer standard Java annotation over framework specific annotations e.g. in Hibernate, its's better to use @Entity annotation from JPA rather than @Entity annotation from Hibernate itself.


Now, coming back to difference between @Secured and @PreAuthozie/@PostAuthorized, even though both are Spring security annotations, @PreAuthorize and @PostAuthorize are newer and more powerful annotations, which can be used to implement even complex security constraints on methods.

The key difference between @Secured and @PreAuthorize Annotation is that, you cannot use Spring EL (Expression language) with @Secured but @PreAuthorize allows Spring EL expressions in it. This means you can have more powerful conditions to implement method level security.


On the other hand, Spring's @PreAuthorize and @PostAuthorize annotations are the preferred annotations for applying method-level security in Java application because they supports Spring Expression Language out of the box, and provide expression-based access control.


@PreAuthorize is suitable for verifying authorization before entering into method. It can use account, the roles/permissions of logged-in User, argument passed to the method to preform checks before allowing access to the method etc.

On the other hand, @PostAuthorize is used to verify authorization after execution of method, which means it can be used for verifying authorization on returned values. Spring EL provides returnObject object that can be accessed in expression language and reflects the actual object returned from method. 

You can compare various attributes of returnObject with the logged-in user to implement restrictions.


For example, suppose there are a couple of methods in your OrderService class as shown below:


public interface OrderService {


List<Order> getAllOrders();


Order findOrderById(int orderId);


void modifyOrder(Order o);


void deleteOrder(int id);


}

Now, you can secure this methods by using @Secured annotation of Spring Security as follows:

@Secured("ROLE_ADMIN")
public Order findOrderById(int orderId);


@Secured({"ROLE_TRADER", "ROLER_OPERATIONS"} )
public void modifyOrder(Order o);


This means only users with ROLE_ADMIN can invoke findOrderById() method and user with either ROLE_TRADER and ROLE_OPERATIONS can invoke modifyOrder() method. 

You can replace @Secured with @RolesAllowed annotation without impacting functionality as shown below:

@RolesAllowed("ROLE_ADMIN")
public Order findOrderById(int orderId);


@RolesAllowed({"ROLE_TRADER", "ROLER_OPERATIONS"} )
public void modifyOrder(Order o);


Only problem with @Secured is that you cannot express complex logic e.g. if you want to restrict access to deleteOrder() to a user which has both ROLE_TRADER and ROLE_OPERATIONS then you cannot do that. 

For that you need to use the @PreAuthorize annotation of Spring Security.

The @PreAuthroize annotations support Spring EL and expression based access control which makes it easy to apply complex logic as shown below:


@PreAuthorize("hasRole('ROLE_ADMIN') AND hasRole('ROLE_TRADER')")
void deleteOrder(int id);


Similarly, you can use @PostAuthorize annotation to restrict user to see only his orders and not others. You can do this by using authentication object which Spring EL has access as shown below:


@PostAuthorize ("returnObject.trader == authentication.name")
public Order findOrderById(int orderId);


Now, a logged in user with ROLE_TRADER can only see his orders and not others.


What is difference between @Secured, @RolesAllowed, and @PostAuthorize Annotation?

Now that you know what is @Secured and @RollesAllowed annotation and how to use them, let's revise the key difference between them. 

They both provide same functionality when it comes to method level security but one is Spring Security proprietary annotation while other is a standard annotation provided by JSR 250. 

The benefit of using a standard annotation is that you no longer depend upon a particular framework e.g. by using @Entity annotation of JPA, you can implement ORM solutions either using Hibernate or any other JPA provider e.g. Oracle's TopLink. 

In short, use @RolesAllowed over @Secured wherever possible.


@PreAuthorize and @PostAuthoriaze is different in a way that it is more powerful then the @Secured and @RolesAllowed. It allows for SpEL expression for a more fine-grained access control. You can use SpEL expressions specify complex conditions e.g. by using AND operator we have used in our example. 

Similarly, @PostAuthorize annotation gives you a chance to verify authorization after method execution. You can implement things like a user can only access his orders using returnObject available to SpEL while using @PostAuthorize annotation.


In short, If you don't need expression etc. go with the standard annotations to limit the dependency on spring classes. But that all is IMHO of course.


That's all about difference between @Secured, @RolesAllowed, @PreAuthorize, and @PostAuthorize annotations in Spring Security. Even though all these annotations are used to implement method security, you must remember the subtle difference between them. @Secured is an old Spring Security annotation while @RolesAllowed is a standard Java annotation defined in JSR 250. Wherever possible, prefer @RolesAllowed over @Secured.

Similarly, if you need to implement complex logic and need Spring EL support then use @PreAuthorize and @PostAuhtorize. In general, Spring Security is very important framework and skill for both job and career and you should spend time learning it. 

No comments:

Post a Comment