antMatchers Spring Security pattern with changeable URL user ID
Solution 1
This works for me:
antMatchers("/account/{\\d+}/download").access("hasAnyAuthority('ROLE_TOKENSAVED')")
Notice the curly braces around the path variable representing the ID.
Solution 2
Though what Bohuslav suggest works, it is not complete. According to the documentation for AntPathMarcher: http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/util/AntPathMatcher.html
You need to specify the path variable with the regex:
{spring:[a-z]+} matches the regexp [a-z]+ as a path variable named "spring"
If you don't, you may expose other routes. For example:
.authorizeRequests()
.antMatchers(HttpMethod.GET, "/users/{^[\\d]$}").authenticated()
.antMatchers("/users/**").hasAuthority("admin")
and these methods on a UserController:
@ResponseBody
@RequestMapping(value = "/users/{userId}", method = RequestMethod.GET)
public User getUser(@PathVariable("userId") Object id) {
return userService.getUserById(userId);
}
@ResponseBody
@RequestMapping(value = "/users/roles", method = RequestMethod.GET)
public List<String> getAllRoles() {
return userService.getAllRoles();
}
Because you didn't specify path variable, userId
, users will be able to do a GET request on "/users/roles" without having the admin authority. Also other futures routes like "/users/test" will also be exposed even if admin authorization is required. To prevent that:
antMatchers("/account/{accountId:\\d+}/download")
.access("hasAnyAuthority('ROLE_TOKENSAVED')")
if your path variable's name was "accountId"
azalut
Updated on April 09, 2020Comments
-
azalut about 4 years
I was looking for the answer for a long time but couldnt find anything productive
In my rest service I keep some functionality under: /account/{id}/download and I would like to set the acces ROLE in SecurityConfig java file, that only ROLE_TOKENSAVED users can access this url
How should the pattern look like, when {id} is changeable?
I tried some regexp patterns, but nothing worked as I wanted, here are some of my attempts:
1. antMatchers("account/**/download").access(somerolehere) 2. antMatchers("account/\\d/download").access(somerolehere) 3. antMatchers("account/[\\d]/download").access(somerolehere)
thanks in advance for your anserwers :)
edit:
@Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/admin**").access("hasRole('ROLE_ADMIN')") .antMatchers("/account*//**").access("hasRole('ROLE_USER') or hasRole('ROLE_ADMIN')") .antMatchers("/account/\\d+/download").access("hasRole('ROLE_TOKENSAVED')") .antMatchers("/user**").permitAll() //othercode... }
-
azalut over 9 yearsyup it worked, but only when I comment .antMatchers("/account*//**").access("hasRole('ROLE_USER') or hasRole('ROLE_ADMIN')") pattern, how to reconcile these two patterns?
-
Bohuslav Burghardt over 9 yearsBecause that matcher is more general. Matchers must be ordered from most specific to least specific. So put the
/account/{\\d+}/download
matcher before it. -
azalut over 9 yearsbut why should I have added {} brackets to the pattern? because controllers use: {id} pattern to take PathVariable from it?
-
Bohuslav Burghardt over 9 years@azalut When you look at the
AntPathMatcher
JavaDoc it says this: "URI template variables are expressed through curly brackets ('{' and '}')". So this is just specific syntax for Ant matchers. -
S_K about 5 yearsNote that
\d
is for a numeric value, I have string parameter in the path. So, I have used\w
.