feat: API 예외 처리 및 오류 응답 형식 표준화

- Spring @ControllerAdvice를 사용하여 예외 처리 로직 중앙화
- 4xx, 5xx 오류에 대한 일관된 JSON 응답 형식 적용
- elink-online-common MessageUtil 클래스에 makeJsonErrorMessage 메소드 수정
This commit is contained in:
pksup
2025-12-11 13:32:46 +09:00
parent 0b98c8d11f
commit 7b3807300b
29 changed files with 1583 additions and 50 deletions
@@ -87,8 +87,10 @@ public class ApiAdapterController implements HttpAdapterServiceKey {
if (adptUri == null) {
logError(servletRequest);
// throw new Exception("can not find Adapter Uri");
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("can not find Adapter Uri");
String errorMsg = MessageUtil.makeJsonErrorMessage(MessageUtil.ERROR_CODE_SERVICE_NOT_FOUND, "can not find Adapter Uri");
return ResponseEntity.status(HttpStatus.NOT_FOUND)
.contentType(MediaType.APPLICATION_JSON)
.body(errorMsg);
}
//Received time , jwhong
@@ -100,8 +102,10 @@ public class ApiAdapterController implements HttpAdapterServiceKey {
AdapterGroupVO adapterGroupVO = AdapterManager.getInstance().getAdapterGroupVO(adapterGroupName);
AdapterVO adapterVO = AdapterManager.getInstance().getAdapterVO(adapterGroupName, adapterName);
if (adapterVO == null) {
// throw new Exception("Adapter not found error");
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Adapter not found error");
String errorMsg = MessageUtil.makeJsonErrorMessage(MessageUtil.ERROR_CODE_AP_ERROR, "Adapter not found error");
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.contentType(MediaType.APPLICATION_JSON)
.body(errorMsg);
}
Properties httpProp = AdapterPropManager.getInstance().getProperties(adapterVO.getPropGroupName());
@@ -152,17 +156,19 @@ public class ApiAdapterController implements HttpAdapterServiceKey {
}
} catch (HttpStatusException e) {
logger.warn("ApiAdapterController] " + adapterGroupName + "-" + adapterName + ">>" + e.getMessage());
String errorMsg = MessageUtil.makeErrorMessageByMessageType(adptMsgType, encode, e.getCode(),
String errorMsg = MessageUtil.makeErrorMessageByMessageType(adptMsgType, encode, MessageUtil.ERROR_CODE_AP_ERROR,
e.getMessage(), errorResponseFormat);
responseEntity = ResponseEntity.status(e.getStatus()).contentType(mediaType).body(errorMsg);
} catch (JwtAuthException e) {
logger.error(adapterGroupName + "-" + adapterName + ">>" + e.getMessage(), e);
String errorMsg = MessageUtil.makeErrorMessageByMessageType(adptMsgType, encode, e.getCode(),
String errorMsg = MessageUtil.makeErrorMessageByMessageType(adptMsgType, encode, MessageUtil.ERROR_CODE_AUTH_FAIL,
e.getMessage(), errorResponseFormat);
responseEntity = ResponseEntity.status(HttpStatus.UNAUTHORIZED).contentType(mediaType).body(errorMsg);
} catch (Exception e) {
logger.error(adapterGroupName + "-" + adapterName + ">>" + e.getMessage(), e);
responseEntity = ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).contentType(mediaType).body(e);
String errorMsg = MessageUtil.makeErrorMessageByMessageType(adptMsgType, encode, MessageUtil.ERROR_CODE_AP_ERROR,
e.getMessage(), errorResponseFormat);
responseEntity = ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).contentType(mediaType).body(errorMsg);
} finally {
/**
* 로깅 인터셉터에 데이터를 전달하기 위한 처리
@@ -0,0 +1,65 @@
package com.eactive.eai.authserver.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.core.AuthenticationException;
import org.springframework.validation.BindException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.NoHandlerFoundException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Configuration
@ControllerAdvice
public class WebMvcConfig {
@ExceptionHandler({
HttpMessageNotReadableException.class,
MethodArgumentNotValidException.class,
MissingServletRequestParameterException.class,
BindException.class
})
public String handleBadRequest(HttpServletRequest request, HttpServletResponse response, Exception ex) {
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
request.setAttribute("_authServerStatusCode", HttpServletResponse.SC_BAD_REQUEST);
request.setAttribute("errorMessage", "400 Bad Request");
return "forward:/error.jsp";
}
@ExceptionHandler(NoHandlerFoundException.class)
public String handleNotFound(HttpServletRequest request, HttpServletResponse response, Exception ex) {
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
request.setAttribute("_authServerStatusCode", HttpServletResponse.SC_NOT_FOUND);
request.setAttribute("errorMessage", "404 Not Found");
return "forward:/error.jsp";
}
@ExceptionHandler(AuthenticationException.class)
public String handleUnauthorized(HttpServletRequest request, HttpServletResponse response, Exception ex) {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
request.setAttribute("_authServerStatusCode", HttpServletResponse.SC_UNAUTHORIZED);
request.setAttribute("errorMessage", "401 Unauthorized");
return "forward:/error.jsp";
}
@ExceptionHandler(AccessDeniedException.class)
public String handleAccessDenied(HttpServletRequest request, HttpServletResponse response, Exception ex) {
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
request.setAttribute("_authServerStatusCode", HttpServletResponse.SC_FORBIDDEN);
request.setAttribute("errorMessage", "403 Forbidden");
return "forward:/error.jsp";
}
@ExceptionHandler(Exception.class)
public String handleException(HttpServletRequest request, HttpServletResponse response, Exception ex) {
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
request.setAttribute("_authServerStatusCode", HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
request.setAttribute("errorMessage", ex.getMessage());
return "forward:/error.jsp";
}
}
@@ -14,6 +14,8 @@ import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import javax.servlet.http.HttpServletResponse;
@Configuration
@EnableWebSecurity
@Order(1)
@@ -29,8 +31,23 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
.headers().frameOptions().disable()
.and()
.authorizeRequests()
.antMatchers("/error.jsp").permitAll()
.antMatchers("/**").permitAll()
.and()
.exceptionHandling()
.authenticationEntryPoint((request, response, authException) -> {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
request.setAttribute("_authServerStatusCode", HttpServletResponse.SC_UNAUTHORIZED);
request.setAttribute("errorMessage", "401 Unauthorized");
request.getRequestDispatcher("/error.jsp").forward(request, response);
})
.accessDeniedHandler((request, response, accessDeniedException) -> {
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
request.setAttribute("_authServerStatusCode", HttpServletResponse.SC_FORBIDDEN);
request.setAttribute("errorMessage", "403 Forbidden");
request.getRequestDispatcher("/error.jsp").forward(request, response);
})
.and()
.formLogin();
// .and()
// .httpBasic();
@@ -21,6 +21,7 @@ import org.springframework.web.bind.annotation.RestController;
import com.eactive.eai.adapter.http.dynamic.filter.JwtAuthException;
import com.eactive.eai.authserver.service.OAuth2Manager;
import com.eactive.eai.common.util.Logger;
import com.eactive.eai.common.util.MessageUtil;
@RestController
@RequestMapping("/auth/oauth/v2")
@@ -75,20 +76,12 @@ public class BearerTokenContoller {
return ResponseEntity.ok(resObject);
} catch (JwtAuthException e) {
logger.error(e);
JSONObject errorJson = new JSONObject();
errorJson.put("error", e.getCode());
errorJson.put("error_description", e.getMessage());
resObject.putAll(errorJson);
return ResponseEntity.status(401).body(resObject);
String errorJson = MessageUtil.makeJsonErrorMessage(MessageUtil.ERROR_CODE_AUTH_FAIL, e.getMessage());
return ResponseEntity.status(401).body(errorJson);
} catch (Exception e) {
logger.error(e);
JSONObject errorJson = new JSONObject();
errorJson.put("error", "invalid_request");
errorJson.put("error_description", e.getMessage());
resObject.putAll(errorJson);
return ResponseEntity.status(500).body(resObject);
String errorJson = MessageUtil.makeJsonErrorMessage(MessageUtil.ERROR_CODE_AP_ERROR, e.getMessage());
return ResponseEntity.status(500).body(errorJson);
}
}
@@ -16,6 +16,7 @@ import org.springframework.web.filter.OncePerRequestFilter;
import com.eactive.eai.adapter.http.dynamic.filter.JwtAuthException;
import com.eactive.eai.common.util.Logger;
import com.eactive.eai.common.util.MessageUtil;
@Component
public class BearerTokenFilter extends OncePerRequestFilter{
@@ -35,8 +36,6 @@ public class BearerTokenFilter extends OncePerRequestFilter{
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain) throws IOException, ServletException {
JSONObject resObject = new JSONObject();
try {
String auth = request.getHeader("Authorization");
@@ -62,23 +61,16 @@ public class BearerTokenFilter extends OncePerRequestFilter{
filterChain.doFilter(request, response);
} catch (JwtAuthException jae) {
logger.debug(jae.getMessage());
JSONObject errorJson = new JSONObject();
errorJson.put("error", jae.getCode());
errorJson.put("error_description", jae.getMessage());
resObject.putAll(errorJson);
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); // 401 설정
String errorJson = MessageUtil.makeJsonErrorMessage(MessageUtil.ERROR_CODE_AUTH_FAIL, jae.getMessage());
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write(resObject.toJSONString());
response.getWriter().write(errorJson);
} catch (Exception e) {
logger.error(e.getMessage());
JSONObject errorJson = new JSONObject();
errorJson.put("error", "invalid_request");
errorJson.put("error_description", e.getMessage());
resObject.putAll(errorJson);
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); // 500 설정
String errorJson = MessageUtil.makeJsonErrorMessage(MessageUtil.ERROR_CODE_AP_ERROR, e.getMessage());
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write(resObject.toJSONString());
response.getWriter().write(errorJson);
}
}
}
@@ -1,14 +1,11 @@
package com.eactive.eai.authserver.custom;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.Principal;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Signature;
import java.security.spec.X509EncodedKeySpec;
import java.time.LocalDateTime;
import java.util.Base64;
import java.util.HashMap;
@@ -39,7 +36,6 @@ import org.springframework.web.bind.annotation.ResponseBody;
import com.eactive.eai.adapter.http.dynamic.filter.JwtAuthException;
import com.eactive.eai.authserver.config.IssueLimitOAuth2Exception;
import com.eactive.eai.authserver.config.AuthorizationServerConfig;
import com.eactive.eai.authserver.config.RequestContextData;
import com.eactive.eai.authserver.dao.TokenIssuanceLogDAO;
import com.eactive.eai.authserver.service.OAuth2Manager;
@@ -48,8 +44,10 @@ import com.eactive.eai.authserver.vo.ClientVO;
import com.eactive.eai.common.dao.DAOException;
import com.eactive.eai.common.logger.EAIDBLogControl;
import com.eactive.eai.common.util.Logger;
import com.eactive.eai.common.util.MessageUtil;
import com.eactive.eai.common.util.UUID;
import com.eactive.eai.data.entity.onl.authserver.TokenIssuanceLog;
import com.fasterxml.jackson.databind.ObjectMapper;
@Controller
public class KjbMGOAuth2Controller {
@@ -63,7 +61,7 @@ public class KjbMGOAuth2Controller {
@RequestMapping(value = "/mapi/oauth2/token", method = RequestMethod.POST, produces = "application/json; charset=\"UTF-8\"")
@ResponseBody
public KjbMGOAuth2AccessTokenResponse token(@RequestBody KjbMGOAuth2AccessTokenRequest tokenRequest,
public ResponseEntity<String> token(@RequestBody KjbMGOAuth2AccessTokenRequest tokenRequest,
HttpServletRequest request, HttpServletResponse response) {
if (logger.isDebug()) {
logger.debug(tokenRequest.toString());
@@ -96,7 +94,7 @@ public class KjbMGOAuth2Controller {
ClientDetails clientDetails = OAuth2Manager.getInstance().getClientDeatilsStore().get(clientId);
verifyClient(clientDetails, clientId, scopeSet);
String traceId = UUID.randomUUID().toString().replace("-", "");
String traceId = UUID.randomUUID().toString().replace("-", "");
response.setHeader(HEADER_TRACEID, traceId);
HashMap<String, String> authorizationParameters = new HashMap<String, String>();
@@ -123,19 +121,22 @@ public class KjbMGOAuth2Controller {
responseToken.setExpiresOn(System.currentTimeMillis() + (token.getExpiresIn() * 1000));
responseToken.setScope(tokenRequest.getScope());
responseToken.setResource(tokenRequest.getResource());
// 성공 시 JSON 문자열로 변환하여 반환
ObjectMapper mapper = new ObjectMapper();
String successJson = mapper.writeValueAsString(responseToken);
return ResponseEntity.ok(successJson);
} catch (JwtAuthException e) {
response.setStatus(NumberUtils.toInt(StringUtils.left(e.getCode(), 3), HttpStatus.UNAUTHORIZED.value()));
responseToken.setResponseCode(e.getCode());
responseToken.setResponseMessage(e.getMessage());
String errorJson = MessageUtil.makeJsonErrorMessage(MessageUtil.ERROR_CODE_AUTH_FAIL, e.getMessage());
int statusCode = NumberUtils.toInt(StringUtils.left(e.getCode(), 3), HttpStatus.UNAUTHORIZED.value());
return ResponseEntity.status(statusCode).body(errorJson);
} catch (Exception e) {
logger.error(e.getMessage());
response.setStatus(HttpStatus.UNAUTHORIZED.value());
responseToken.setResponseCode(
String.format("%d%s%s", HttpStatus.UNAUTHORIZED.value(), SERVICE_CODE_ACCESS_TOKEN, "00"));
responseToken.setResponseMessage("Unauthorized. [Unknown]");
String errorJson = MessageUtil.makeJsonErrorMessage(MessageUtil.ERROR_CODE_AUTH_FAIL, "Unauthorized. [Unknown]");
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(errorJson);
}
return responseToken;
}
private void verifyClient(ClientDetails clientDetails, String clientId, Set<String> scopeSet)