In Spring MVC with Spring Security, is it possible to achieve this?
@Override WebSecurityConfigurerAdapter.configure(HttpSecurity)
@Override
protected void configure(HttpSecurity http) throws Exception
{
    http
            .authorizeRequests()
            .mvcMatchers("/users/{authentication.principal.username}").hasAnyRole(ADMIN, MANAGER)
            .antMatchers("/users/**").hasRole(ADMIN)
            .anyRequest().authorized()
    ...
}
/users/** is a restricted area and should be accessible by admins only. But managers should still be able to see their own profile (/users/user_with_manager_role), and only their own profile, not those of any other users (regardless of their role).
I've found a solution in Andrew's answer. My Code now looks like this:
WebSecurityConfigurerAdapter
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true) // added this annotation
public class SecurityConfig extends WebSecurityConfigurerAdapter
@Override WebSecurityConfigurerAdapter.configure(HttpSecurity)
@Override
protected void configure(HttpSecurity http) throws Exception
{
    http
            .authorizeRequests()
            // removed /users handling
            .anyRequest().authorized()
    ...
}
UsersController
@Controller
@RequestMapping("/users")
public class UsersController
{
    @GetMapping("{username}")
    @PreAuthorize("authentication.principal.username == #username) || hasRole('ADMIN')")
    public String usersGet(@PathVariable("username") String username)
    {
        // do something with username, for example get a User object from a JPA repository
        return "user";
    }
}
                In any @Controller , @RestController annotated bean you can use Principal directly as a method argument. @RequestMapping("/users/{user_id}") public String getUserInfo(@PathVariable("user_id") Long userId, Principal principal){ // test if userId is current principal or principal is an ADMIN .... }
Step 1: Add the security jar or dependency in your application. Step 2: Create a security config class and extend the WebSecurityConfigurerAdapter class. Step 3: Add the annotation @EnableWebSecurity on top of the class. Step 4: For authentication, override the method configure(AuthenticationManagerBuilder auth) .
You need to declare SecurityFilterChain and WebSecurityCustomizer beans instead of overriding methods of WebSecurityConfigurerAdapter class.
I'm afraid it's not possible: when this configuration is being set up, it has no info about {authentication.principal.username} which will be resolved at some point in future.
But Spring gives you a bunch of built-in method security expressions you can annotate your methods with.
Starting from a simple expression like @PreAuthorize("hasRole('ADMIN')"), you might end up with a custom one:
@XMapping(path = "/users/{username}")
@PreAuthorize("@yourSecurityService.isMyPage(authentication.principal, #username)")
public void yourControllerMethod(@PathVariable String username);
@yourSecurityService.isMyPage(authentication.principal, #username) refers to your @Service method public boolean isMyPage(Principal, String).
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