0

I'm using Spring Boot 2 and Spring Security 11 with Java 11. I'm creating an API-only application and trying to secure endpoints relating to "users" ...

@Configuration
@EnableWebSecurity
class SecurityConfiguration extends WebSecurityConfigurerAdapter {
    ...

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
        .csrf().disable()
        .exceptionHandling().authenticationEntryPoint(jwtUnAuthorizedResponseAuthenticationEntryPoint).and()
                .sessionManagement().sessionCreationPolicy(
                        SessionCreationPolicy.STATELESS).and()
        .authorizeRequests()
        .antMatchers("/api/users").access("hasRole('ADMIN')")
        .anyRequest().authenticated();

        http
        .addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);

        http
        .headers()
        .frameOptions().sameOrigin()
        .cacheControl(); //disable caching
    }

I have this RestController for users ...

@RestController
@RequestMapping("/api/users")
public class UserController {

    @Autowired
    private UserService userService;

    @GetMapping
    public ResponseEntity<List<User>> find() {
        List<User> foundUsers = userService.find();
        return ResponseEntity.ok(foundUsers);
    }
    
    @GetMapping("/{id}")
    public ResponseEntity<User> read(@PathVariable("id") UUID id) {
        User foundUser = userService.findById(id);
        if (foundUser == null) {
            return ResponseEntity.notFound().build();
        } else {
            return ResponseEntity.ok(foundUser);
        }
    }
    
    @PostMapping
    @ResponseStatus(code = HttpStatus.CREATED)
    public void create(@Valid @RequestBody User user) {
        userService.create(user);
    }
    
    @PutMapping("/{id}")
    public ResponseEntity<User> update(@RequestBody User card, @PathVariable UUID id) {
        final User updatedUser = userService.update(id, card);
        if (updatedUser == null) {
            return ResponseEntity.notFound().build();
        } else {
            return ResponseEntity.ok(updatedUser);
        }
    }

}

I would like to expand my security to allow people to access the GET and PUT endpoints if the ID of the user with which they are logged in matches the ID of the request. Is it possible to add a rule for that in HttpSecurity or do I allow everyone to access those endpoints and then add Java in the REST methods to check the user that is logged in?

satish
  • 703
  • 5
  • 23
  • 52

1 Answers1

1

Enable the method security and use @PreAuthorize to annotate the controller method that you want to secure. @PreAuthorize allow to define a SpEL which will be evaluated as boolean to see if that method is allow to be executed.

First enable method security by @EnableGlobalMethodSecurity :

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
class SecurityConfiguration {
    

}

Then in the controller method :

@GetMapping("/{id}")
@PreAuthorize("principal.id = #id")
public ResponseEntity<User> read(@PathVariable("id") UUID id) {
 
}
  • You can use #xxx to access the parameter of the protected method.
  • principal is the built in expression that access the user object stored in the SecurityContext. It depends on how you customize the user object.
  • You can also use built-in expression authentication to access the Authentication object in SecurityContext for the checking.
Ken Chan
  • 84,777
  • 26
  • 143
  • 172