Reputation: 663
In my RestController I have POST method which returns different object based on user role:
@PostMapping("getlocal")
@PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_USER')")
public ResponseEntity<LocalDto> getLocal(@RequestBody LocalRequest localRequest){
return status(OK).body(localService.findLocalBylocalId(localRequest));
}
Service method:
public LocalDto findLocalBylocalId(LocalRequest localRequest) {
Role role = userRoleRepository.findByUsername(localRequest.getUsername());
if(role == Role.ROLE_ADMIN) //return localDto infromation object for ADMIN
else if(role == Role.ROLE_USER) //return localDto information for USER
}
LocalRequest contains username of current logged in user.
The problem is when user will authenticate and hit this endpoint he can pass to RequestBody admin's username. In this case he will get access to admin resources even if he is logged as USER.
How to avoid this situation and modify the code?
Upvotes: 1
Views: 810
Reputation: 21720
You can access the currently authenticated username by specifying Principal
as an argument. For example:
@PostMapping("getlocal")
@PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_USER')")
public ResponseEntity<LocalDto> getLocal(Principal principal){
return status(OK).body(localService.findLocalBylocalId(principal.getName()));
}
This works because Spring MVC will resolve the Principal
argument from the HttpServletRequest.getUserPrincipal()
method and Spring Security overrides the method to align with the currently logged in user. You would then need to update your LocalDto to accept a username instead of a Localrequest
.
Alternatively, you can also resolve the entire Spring Security Authentication in the same way since the HttpServletRequest.getUserPrincipal()
will be an Authentication
.
@PostMapping("getlocal")
@PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_USER')")
public ResponseEntity<LocalDto> getLocal(Authentication authentication){
return status(OK).body(localService.findLocalBylocalId(principal.getName()));
}
This gives you access to the roles without needing to look them up again. The disadvantage of this approach is that you are now relying on Spring Security's API directly.
You can also consider using the @AuthenticationPrincipal
annotation to decouple yourself from Spring Security. This approach is the best if you need access to more than just the username because you can still be decoupled from Spring Security, but it also involves more work (i.e for username/password authentication you need a custom UserDetailsService
, custom UserDetails
). Because the amount of work/variables here, it is difficult to provide more guidance than a link to the documentation without further details.
Upvotes: 1