Search code examples
springspring-securityspring-bootspring-el

Spring Boot property in @Preauthorize


I'm setting up a Spring Boot (v1.2.6) web project and using Spring Security (v3.2.8). I've found the @PreAuthorize annotation so handy, but I don't know if there's a way to read Boot's properties from the SpEL in the annotation. I'm trying to do it this way:

@PreAuthorize("mysecurity.permit")

With the property declared in application.yml:

mysecurity:
    permit: true

But I'm getting

Failed to evaluate expression 'mysecurity.permit'

I've made an attempt with @mysecurity.permit and ${mysecurity.permit} too, with the same result. It seems possible to declare a method in a service and access it in @service.isMySecurityPermited() way, however I would be pleased to know if I'm able to access the property directly.


Solution

  • The values used in an annotation must be constants. They are evaluated at compile time, and while they may be retained for use at runtime they aren't re-evaluated. So you can use an expression that's evaluated by SpEL, or you can write a helper method that is referenced within the annotation value.

    If you look at the OnExpressionCondition implementation, you will notice that it gets the value passed to the annotation, which in the case linked in your comment would be something like @ConditionalOnExpression("${server.host==localhost} or ${server.port==8080} ") The annotation simply gets the text value, it has no idea what the text represents, it just knows it's a string. It's in the processing of the annotation value within OnExpressionCondition that the String value takes meaning. They take the String value and pass it to a BeanExpressionResolver for resolution.

    So, in your PreAuthorize solution, which based on http://forum.spring.io/forum/spring-projects/security/100708-spel-and-spring-security-3-accessing-bean-reference-in-preauthorize also passes it to an expression processor, you should be able to use spring's expression language to reference any bean property.

    I'm not in a situation to test it currently, but from that thread it seems like you could do something like

    @Component
    public class MyBean {
      @Value("${mysecurity.permit}")
      private Boolean permit;
    
      public boolean isPermitted() { return permit; }
    
      @PreAuthorize( "@myBean.isPermitted()" )
      public blah myMethod() {
        // do stuff
      }
    }