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
This should work:
@Value("${mysecurity.permit}")
private Boolean permit;
Then use:
@PreAuthorize(permit)
But you need to properly set configuration file, to allow Spring access it. Read here: https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html
UPDATE: Did you configure bean for a property placeholder? For example:
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:com/foo/app.properties</value>
</list>
</property>
</bean>
This maybe a generic way to evaluate expressions which i want to share with you:
@Component("AuthorizationComponent")
public final class AuthorizationComponent {
private final static Logger logger = Logger.getLogger(AuthenticationUtils.class.getName());
private static SpelExpressionParser parser;
static {
parser = new SpelExpressionParser();
}
@Autowired
private Environment environment;
public boolean evaluateExpression(final String propertyKey) {
return checkExpression(environment.getProperty(propertyKey));
}
public static boolean checkExpression(String securityExpression) {
logger.info("Checking security expression [" + securityExpression + "]...");
SecurityContext securityContext = SecurityContextHolder.getContext();
Authentication authentication = securityContext.getAuthentication();
Expression exp = parser.parseExpression(securityExpression);
SecurityExpressionRoot context = new CustomMethodSecurityExpressionRoot(authentication);
boolean result = exp.getValue(context, Boolean.class);
logger.info("Check result: " + result);
return result;
}
}
And in yaml config file you can configure the path and authorization expression, something like that:
preAuthorize:
whatever:
post: hasRole('MY_ROLE') OR hasAuthority('MY_AUTHORITY')
Then you could use it like that over your method:
@PreAuthorize("@AuthorizationComponent.evaluateExpression('preAuthorize.whatevert.post')")
@RequestMapping(value = "", method = RequestMethod.POST)
public ResponseEntity<Void> addQuestion(@Valid @RequestBody BodyRestDTO bodyRestDTO){
//Code implementation
return new ResponseEntity<Void>(HttpStatus.CREATED);
}
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
}
}