I'm trying to do method security in Spring Service by annotating it with @PreAuthorized annotation. I want to check if the id claim from the JWT token equals id field from my Request Body, I'm trying to do
@PreAuthorize("r.id == principal.getId()")
public ResponseEntity<?> update(UpdateRequest r) {
return ResponseEntity.ok().build();
}
But it seems like it's trying to use Spring built-in UserDetails without my custom logic.
I'm sure that in my public class JwtAutentificationFilter extends OncePerRequestFilter
using my custom UserDetails. I've tried Custom class principal in @PreAuthorize solution, where it was suggested to make custom Bean for that and I got an error
Failed to evaluate expression @decider.mayUpdate(principal,r.id)'
Where it was basically this
public static boolean mayUpdate(Object principal, Long id){
CustomUserDetails user = (CustomUserDetails) principal;
return user.getId().equals(id);
}
I know that in every method I can get security context and do something like
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
CustomUserDetails userDetails = (CustomUserDetails) auth.getPrincipal();
if(!userDetails.getId().equals(r.getId())){
...throw an error
}
But I'm going to have a lot of methods, and I don't want to do it in such a straight way. So I want to know if there's a way to put my custom principal into @PreAuthorized or do this authorization in some easier way!
I found a way to fix this!
If any of you need to use custom UserDetails in @PreAuthtorize, create a new bean where you put your Authorization logic using SecurityContext you can do it like this:
You should annotate the method you want to secure like
@PreAuthorize("@decider.tokenIdEqualsIdFromRequest(#r.id)")
public ResponseEntity<?> update(UpdateRequest r) {
return ResponseEntity.ok().build();
}
And you have to create the bean where your logic using security context will be located, for me it's like
@Service
public class Decider {
public static boolean tokenIdEqualsIdFromRequest(Long id){
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
CustomUserDetails userDetails = (CustomUserDetails) auth.getPrincipal();
return userDetails.getId().equals(id);
}
}