Learn Spring Security
Contents
PostAuthorize
@PostAuthorize does the same job as @PreAuthorize, but does it after the execution of the annotated service method. In doing so we get access to the return value of the method which can be used to make authorization decision inside @PostAuthorize. But there is a caveat that any operation which changes the state of the application must be avoided.
Secure view profile service
Though we have secured the below service method with VIEW_PROFILE permission, any authenticated user can view other user's profile because this permission is assigned to all the Roles.
@PreAuthorize(Authority.VIEW_PROFILE)
public AppUser get(Long userId) {
return appUserRepository.findById(userId)
.orElse(null);
}
In order to secure this service method we need to ensure that the authenticated user and the requested user profile are same.
We can get the authenticated user's username from Authentication object in SecurityContextHolder. And Spring Security provides an in-built expression to access this Authentication object using SpEL expression authentication before the execution of the method.
But unless we find the requested user profile from the repository and confirm that it is same as the authenticated user we can't authorize. @PostAuthorize allows us to access this requested user profile from the return value using SpEL expression returnObject after the execution of the method.
@PreAuthorize(Authority.VIEW_PROFILE)
@PostAuthorize("returnObject.username == authentication.name")
public AppUser get(Long userId) {
return appUserRepository.findById(userId)
.orElse(null);
}
Here returnObject represents the return value of the method which is AppUser object. We are checking username of the requested AppUser object is equal to the name of the Authentication object after the execution of the method.
Above service returns the AppUser object only for authorized requests post execution, but throws 403 Forbidden error for unauthorized requests. Though the service executes all the time, it doesn't change the state of the application.
Test view profile
Now restart the application, send a GET request to ViewProfile API using Gru to view his own profile and we will be authorized to view his profile.
But we will get 403 Forbidden error if we send the same request to view Gru's user profile using any other user credentials.