Issue
public class ApiKeyFilter implements Filter {
private final Logger log = LoggerFactory.getLogger(ApiKeyFilter.class);
private final ApiKeyRepository apiKeyRepository;
private final SecurityModule securityModule;
private final JsonUtils jsonUtils;
@Autowired
public ApiKeyFilter(ApiKeyRepository apiKeyRepository, SecurityModule securityModule, JsonUtils jsonUtils) {
this.apiKeyRepository = apiKeyRepository;
this.securityModule = securityModule;
this.jsonUtils = jsonUtils;
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//Convert request to httpRequest
RequestWrapper requestWrapper = new RequestWrapper((HttpServletRequest) servletRequest);
HttpServletResponse httpServletResponse = (HttpServletResponse)servletResponse;
String xApiKey = requestWrapper.getHeader("x-api-key");
String sortBodySign = requestWrapper.getHeader("sort-body-sign");
//BLABLABLA Logic
//Compare with client's API key
if (!apiKeyObject.getSignature().equalsIgnoreCase(Hex.toHexString(messageDigest))) {
log.error("Invalid signature, expected: {}, received: {}", Hex.toHexString(messageDigest), apiKeyObject.getSignature());
httpServletResponse.sendError(HttpServletResponse.SC_PRECONDITION_FAILED,
StatusCode.getStatusMessage(StatusCode.VERIFY_SIGNATURE_FAIL));
return;
}
} catch (RuntimeException ex){
log.error("Exception happened: {}", ex.getMessage());
httpServletResponse.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Internal Server Error");
return;
}
filterChain.doFilter(requestWrapper, servletResponse);
}
I am new to spring boot httpServletResponse. May i know why my sendError function didnt return the error message as i write. This is the response message :
{"timestamp":"2021-09-10T09:00:54.146+00:00","status":412,"error":"Precondition Failed"}
I wish to return the message into the response as well.
example :
{"timestamp":"2021-09-11T02:17:06.948+00:00","status":602,"error":"Http Status 602","message":"Invalid Authorization Signature"}
Solution
In your ApiKeyFilter
you should only throw a custom runtime exception (InvalidAuthorizationSignatureException
) instead.
public class InvalidAuthorizationSignatureException extends RuntimeException {
public InvalidAuthorizationSignatureException(String errorMessage, Throwable err) {
super(errorMessage, err);
}
}
Then you need an ExceptionHandler
for this exception that would set the HTTP status and message.
@ControllerAdvice
public class CustomRestExceptionHandler extends ResponseEntityExceptionHandler {
@ExceptionHandler({ InvalidAuthorizationSignatureException.class })
public ResponseEntity<Object> handleInvalidAuthorizationSignature(InvalidAuthorizationSignatureException ex, WebRequest request) {
ApiError apiError = new ApiError(HttpStatus.SC_PRECONDITION_FAILED, StatusCode.getStatusMessage(StatusCode.VERIFY_SIGNATURE_FAIL), errors);
return new ResponseEntity<Object>(apiError, new HttpHeaders(), apiError.getStatus());
}
}
For more details check https://www.baeldung.com/global-error-handler-in-a-spring-rest-api.
Answered By - João Dias