RestSecurityHandlers.java
package com.rbctcsworld.ecommerce.common;
import tools.jackson.databind.ObjectMapper;
import com.rbctcsworld.ecommerce.common.exception.ApiError;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.stereotype.Component;
import java.io.IOException;
/**
* Returns JSON 401 (not logged in / bad token) and 403 (logged in but wrong role)
* instead of Spring Security's default empty 403 for everything.
*/
@Component
public class RestSecurityHandlers implements AuthenticationEntryPoint, AccessDeniedHandler {
private final ObjectMapper mapper;
public RestSecurityHandlers(ObjectMapper mapper) {
this.mapper = mapper;
}
@Override
public void commence(HttpServletRequest req, HttpServletResponse res, AuthenticationException ex) throws IOException {
write(res, req, HttpStatus.UNAUTHORIZED, "Authentication required: missing, invalid or expired token");
}
@Override
public void handle(HttpServletRequest req, HttpServletResponse res, AccessDeniedException ex) throws IOException {
write(res, req, HttpStatus.FORBIDDEN, "You do not have permission to perform this action");
}
private void write(HttpServletResponse res, HttpServletRequest req, HttpStatus status, String message) throws IOException {
res.setStatus(status.value());
res.setContentType(MediaType.APPLICATION_JSON_VALUE);
mapper.writeValue(res.getOutputStream(),
ApiError.of(status.value(), status.getReasonPhrase(), message, req.getRequestURI()));
}
}