by BehindJava

Why is `@PreAuthorize` is not working on Rest Controller in Springboot

Home » java » Why is `@PreAuthorize` is not working on Rest Controller in Springboot

In this tutorial, We are going to learn about @PreAuthorize annotation and its configuration.

@PreAuthorize and @PostAuthorize

  1. The annotations @PreAuthorize and @PostAuthorize provide expression-based access control. redicates can therefore be written in (SpEL (Spring Expression Language.)) [https://www.baeldung.com/spring-expression-language].
  2. The @PreAuthorize annotation validates the given expression before it enters the method, whereas the @PostAuthorize annotation validates it after the method has been executed and may change the result.
  3. In a Java Spring MVC web app that uses Spring Security to log in. Signing in and out is flawless. The two user roles are “ROLE ADMIN” and “ROLE USER.”

@PreAuthorize usecase

  1. Lets assume we have a web app built with Java Spring MVC that logs in with Spring Security. Signing in and out works perfectly. “ROLE ADMIN” and “ROLE USER” are the two user roles.
  2. If you want to restrict access to my method userService.createUser(username) to users with the “ROLE ADMIN” role.
  3. Lets add the @PreAuthorize annotation as shown.
class UserServiceImpl implements UserService {

    @PreAuthorize("hasRole('ROLE_ADMIN')")
    public Integer createUser(String username) throws Exception {
        /* .... */
    }
}
  1. To make the above annotation work. Add @EnableGlobalMethodSecurity(prePostEnabled=true) to your configuration class as shown below.

    @Configuration
    @EnableGlobalMethodSecurity(
    prePostEnabled = true, 
    securedEnabled = true, 
    jsr250Enabled = true)
    public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
        /* .... */
    }

Note:

  1. Spring method security is based on Spring AOP, which is by default implemented with JDK proxies, which is a common issue when using PrePost annotations on controllers.
  2. That is, it works fine on the service layer, which is injected as interfaces in the controller layer, but it is ignored on the controller layer because controllers do not typically implement interfaces.
  3. If you cannot (or do not want to) move the pre-post annotation to the service layer, try to have your controller implement an interface that contains all of the annotated methods as a last resort, use proxy-target-class=true.