I'm using Spring 3.2.3 and Shiro 1.2.0 to secure access to a service. This works, but results in throwing a Shiro-specific exception. I'd like to throw an application-specific exception instead. Is this possible, either with Shiro or mapping at the Spring level? I know I can map controller exceptions to views with Spring, but I'm not sure how to handle it at the service layer. My setup:
Service interface:
public interface CaseService {
Case getCase(Integer id);
}
Service implementation:
@Service
public class CaseServiceImpl implements CaseService {
@RequiresAuthentication
public Case getCase(Integer id) {
// ...
}
}
When testing the above without an authenticated Subject, I do receive an exception as expected, but it is a org.apache.shiro.* one. I tried using Spring's @ExceptionHandler to handle the Shiro exception. It had no effect, but I think it needs to work at the controller layer.
If there isn't a reason you absolutely need use the @RequiresAuthentication annotation you can call the following custom utility class to return the exception you require.
public class UserAuthenticationUtil {
/**
* Check that the current user bound to {@link ThreadLocal} is authenticated.
* @throws ApplicationSpecificException If the current user is not authenticated.
*/
public static void checkUserAuthenticated () throws ApplicationSpecificException {
if (!SecurityUtils.getSubject().isAuthenticated()) {
throw new ApplicationSpecificException("User is not authenticated!");
}
}
}
Here is the code/class that handles the @RequiresAuthentication annotation if you'd like to verify it is the same logic. Here is the API documenation as well.