@ControllerAdvice로 간단한 서블릿 필터 작동
엔드포인트를 보호하기 위해 요청에 정적 키가 있는 특수 헤더가 포함되어 있는지 확인하는 간단한 필터가 있습니다(사용자 인증 없음).그 생각은 그것을 던지는 것입니다.AccessForbiddenException
키가 일치하지 않을 경우 다음과 같이 주석이 달린 클래스로 응답에 매핑됩니다.@ControllerAdvice
. 하지만 난 그걸 해낼 수가 없어요@ExceptionHandler
불리지 않습니다.
클라이언트 키필터
import org.springframework.beans.factory.annotation.Value
import org.springframework.stereotype.Controller
import javax.servlet.*
import javax.servlet.http.HttpServletRequest
@Controller //I know that @Component might be here
public class ClientKeyFilter implements Filter {
@Value('${CLIENT_KEY}')
String clientKey
public void init(FilterConfig filterConfig) {}
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) {
req = (HttpServletRequest) req
def reqClientKey = req.getHeader('Client-Key')
if (!clientKey.equals(reqClientKey)) {
throw new AccessForbiddenException('Invalid API key')
}
chain.doFilter(req, res)
}
public void destroy() {}
}
액세스 금지 예외
public class AccessForbiddenException extends RuntimeException {
AccessForbiddenException(String message) {
super(message)
}
}
예외 컨트롤러
@ControllerAdvice
class ExceptionController {
static final Logger logger = LoggerFactory.getLogger(ExceptionController)
@ExceptionHandler(AccessForbiddenException)
public ResponseEntity handleException(HttpServletRequest request, AccessForbiddenException e) {
logger.error('Caught exception.', e)
return new ResponseEntity<>(e.getMessage(), I_AM_A_TEAPOT)
}
}
어디가 잘못됐나요?간단한 서블릿 필터가 스프링부트의 예외 매핑과 함께 작동할 수 있습니까?
자바 서블릿 사양에서 지정한 대로Filter
항상 a보다 먼저 실행합니다.Servlet
호출됩니다.이제 a.@ControllerAdvice
내부에서 실행되는 컨트롤러에만 유용합니다.DispatcherServlet
. 그래서 a를 이용해서.Filter
그리고 기대하고 있습니다.@ControllerAdvice
아니면 이 경우에.@ExceptionHandler
, 그런 일은 일어나지 않을 겁니다
(JSON 응답 작성을 위해) 필터에 동일한 로직을 넣거나 필터 대신 이 검사를 수행하는 a를 사용해야 합니다.가장 쉬운 방법은 를 확장하고 그냥 재정의하고 구현하는 것입니다.preHandle
방법과 필터의 논리를 그 방법에 넣습니다.
public class ClientKeyInterceptor extends HandlerInterceptorAdapter {
@Value('${CLIENT_KEY}')
String clientKey
@Override
public boolean preHandle(ServletRequest req, ServletResponse res, Object handler) {
String reqClientKey = req.getHeader('Client-Key')
if (!clientKey.equals(reqClientKey)) {
throw new AccessForbiddenException('Invalid API key')
}
return true;
}
}
사용할 수 없습니다.@ControllerAdvice
, 왜냐하면 어떤 컨트롤러에서 예외가 발생할 경우 호출되지만 당신의ClientKeyFilter
가 아닙니다.@Controller
.
당신은 교체해야 합니다.@Controller
와의 주석.@Component
응답 주체와 상태를 다음과 같이 설정합니다.
@Component
public class ClientKeyFilter implements Filter {
@Value('${CLIENT_KEY}')
String clientKey
public void init(FilterConfig filterConfig) {
}
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
String reqClientKey = request.getHeader("Client-Key");
if (!clientKey.equals(reqClientKey)) {
response.sendError(HttpServletResponse.SC_FORBIDDEN, "Invalid API key");
return;
}
chain.doFilter(req, res);
}
public void destroy() {
}
}
Java 클래스의 서블릿 필터는 다음과 같은 용도로 사용됩니다.
- 백엔드에서 리소스에 액세스하기 전에 클라이언트의 요청을 확인합니다.
- 클라이언트로 다시 보내기 전에 서버의 응답을 확인합니다.
필터의 예외 스로우가 @ControllerAdvice에 의해 잡히지 않을 수 있습니다. 왜냐하면 의 값이 DispatcherServlet에 도달하지 못할 수 있기 때문입니다.저는 아래와 같이 프로젝트를 진행하고 있습니다.
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws IOException, ServletException {
String token = null;
String bearerToken = request.getHeader("Authorization");
if (bearerToken != null && (bearerToken.contains("Bearer "))) {
if (bearerToken.startsWith("Bearer "))
token = bearerToken.substring(7, bearerToken.length());
try {
AuthenticationInfo authInfo = TokenHandler.validateToken(token);
logger.debug("Found id:{}", authInfo.getId());
authInfo.uri = request.getRequestURI();
AuthPersistenceBean persistentBean = new AuthPersistenceBean(authInfo);
SecurityContextHolder.getContext().setAuthentication(persistentBean);
logger.debug("Found id:'{}', added into SecurityContextHolder", authInfo.getId());
} catch (AuthenticationException authException) {
logger.error("User Unauthorized: Invalid token provided");
raiseException(request, response);
return;
} catch (Exception e) {
raiseException(request, response);
return;
}
// 오류 응답 래핑
private void raiseException(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
ApiError apiError = new ApiError(HttpStatus.UNAUTHORIZED);
apiError.setMessage("User Unauthorized: Invalid token provided");
apiError.setPath(request.getRequestURI());
byte[] body = new ObjectMapper().writeValueAsBytes(apiError);
response.getOutputStream().write(body);
}
// ApiError 클래스
public class ApiError {
// 4xx and 5xx
private HttpStatus status;
// holds a user-friendly message about the error.
private String message;
// holds a system message describing the error in more detail.
private String debugMessage;
// returns the part of this request's URL
private String path;
public ApiError(HttpStatus status) {
this();
this.status = status;
}
//setter and getters
언급URL : https://stackoverflow.com/questions/30335157/make-simple-servlet-filter-work-with-controlleradvice
'bestsource' 카테고리의 다른 글
memcpy 0바이트를 상수 변수로 - 정의되지 않은 동작? (0) | 2023.09.11 |
---|---|
각2 스프링 부트 서버 사이드 이벤트 (0) | 2023.09.11 |
열 모드에서 flexbox 항목을 랩할 때 컨테이너의 너비가 증가하지 않습니다. (0) | 2023.09.11 |
여러 데이터 프레임 열을 기준으로 주파수 카운트 가져오기 (0) | 2023.09.11 |
C/C++에서 %(모듈러스)를 사용할 수 있는 대안이 있습니까? (0) | 2023.09.11 |