I would like to use @PreAuthorize annotations to secure methods in Spring REST controller, using method parameters, e.g.
@RequestMapping("/something/{myParam}")
@PreAuthorize("@security.check(#myParam)")
public String getSomething(@PathVariable("myParam") Integer myParam) {
//...
}
Spring Security needs a way to discover param names in runtime. When there is no debugging symbols in the compiled class, it is necessary to add a special annotation @P or Spring Data's @Param. So, the method would look like this:
@RequestMapping("/something/{myParam}")
@PreAuthorize("@security.check(#myParam)")
public String getSomething(@PathVariable("myParam") @P("myParam) Integer myParam) {
//...
}
Is it possible to somehow hint Spring Security to use @PathVariable instead and avoid additional annotations like @P?
According to the documentation reading parameter names from annotations is done by AnnotationParameterNameDiscoverer
which can be customized to support the value attribute of any specified annotation. However, I could not find any information on how to customize it.
BTW, I'm using Java 7 and Spring Security 3.2.9.
The @PathVariable annotation is used to extract the value of the template variables and assign their value to a method variable. A Spring controller method to process above example is shown below; @RequestMapping("/users/{userid}", method=RequestMethod.
Simply put, the @PathVariable annotation can be used to handle template variables in the request URI mapping, and set them as method parameters.
@PathVariable is a Spring annotation which indicates that a method parameter should be bound to a URI template variable. If the method parameter is Map<String, String> then the map is populated with all path variable names and values. It has the following optional elements: name - name of the path variable to bind to.
2) @RequestParam is more useful on a traditional web application where data is mostly passed in the query parameters while @PathVariable is more suitable for RESTful web services where URL contains values.
In short, you need to override creating of SecurityExpressionHandler
in the method GlobalMethodSecurityConfiguration#createExpressionHandler
so that set your own ParameterNameDiscoverer
in custom GlobalMethodSecurityConfiguration
.
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MethodSecurityConfiguration extends GlobalMethodSecurityConfiguration {
@Autowired
private ApplicationContext context;
@Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
DefaultMethodSecurityExpressionHandler result = new DefaultMethodSecurityExpressionHandler();
result.setApplicationContext(this.context);
result.setParameterNameDiscoverer(new AnnotationParameterNameDiscoverer(PathVariable.class.getName()));
return result;
}
}
In the sample project you can see result in console output something like this
2016-06-06 17:09:01.635 INFO 2871 --- [nio-8080-exec-4] c.s.so.q37435824.SecurityService: myParam value from PathVariable equals 1
Best regards
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With